问题
I'm currently trying to implement the repositories for my domain objects with the RC of Entity Framework 4.1 and its code first approach. Now I have a domain entity "Voyage" which has a unique identifier encapsulated in the type "VoyageNumber"
public class VoyageNumber
{
private readonly string number;
public VoyageNumber(string number)
{
Validate.NotNull(number, "VoyageNumber is required");
this.number = number;
}
public string Id
{
get { return number; }
}
Now I get an exception when i do this in the configuration of my DbContext:
modelBuilder.Entity<Voyage>().HasKey<VoyageNumber>(k => k.VoyageNumber);
The property 'VoyageNumber' cannot be used as a key property on the entity 'Domain.Model.Voyages.Voyage' because the property type is not a valid key type. Only scalar types, string and byte[] are supported key types.
and also when I try this:
modelBuilder.Entity<Voyage>().HasKey<string>(k => k.VoyageNumber.Id);
The properties expression 'k => k.VoyageNumber.Id' is not valid. The expression should represent a property: C#: 't => t.MyProperty'
Do I really have to trash my VoyageNumber and replace it with a primitive type?
回答1:
This is the limitation. Key members can be only scalar properties directly in the entity. Complex type is represented as complex property which is not supported.
回答2:
For an isolated class you could do a read-only workaround by adding a "get" method to your DbContext that does a SqlQuery<> and maps the table to the class internally (the old-fashioned way).
I've worked up a minimal test-case here: https://github.com/timabell/ef-complex-pk
e.g.
public class TestDbContext : DbContext
{
public IEnumerable<UberWidget> GetUberWidgets()
{
return Database.SqlQuery<WidgetSqlDto>("select WidgetId, Name from Widgets")
.Select(dto => new UberWidget
{
UberWidgetId = new IdWrap { IdWrapId = dto.WidgetId },
Name = dto.Name
});
}
}
回答3:
We can resolve it with the below. Hope it's helpful.
public class TestPaperResultId: ValueObject
{
public TestPaperResultId(string testPaperId, string userId)
{
TestPaperId = testPaperId;
UserId = userId;
}
protected TestPaperResultId() { }
public string TestPaperId { get; protected set; }
public string UserId { get; protected set; }
public override string ToString()
{
return $"{TestPaperId}_{UserId}";
}
}
public class TestPaperResult : AggregateRoot
{
private TestPaperResultId _id;
public TestPaperResultId Id
{
get => _id ?? (_id = new TestPaperResultId(TestPaperId, UserId));
protected set
{
TestPaperId = value.TestPaperId;
UserId = value.UserId;
_id = value;
}
}
public string TestPaperId { get; protected set; }
public string UserId { get; protected set; }
protected TestPaperResult() { }
public TestPaperResult(TestPaperResultId id,
decimal fullmarks)
{
Id = id;
Fullmarks = fullmarks;
}
}
in dbContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<TestPaperResult>()
.Ignore(t => t.Id)
.HasKey(t => new {t.TestPaperId, t.UserId});
}
in Repository:
public Task<TestPaperResult> FindTestPaperResultAsync(TestPaperResultId id)
{
return GetByKeyAsync<TestPaperResult>(id.TestPaperId, id.UserId);
}
来源:https://stackoverflow.com/questions/5522584/ef4-1-code-first-complex-type-as-primary-key