问题 EF4.1 Code First Complex Type作为主键


我目前正在尝试使用实体框架4.1的RC及其代码第一种方法为我的域对象实现存储库。 现在我有一个域实体“Voyage”,它有一个封装在“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; }
    }

现在我在配置DbContext时遇到异常:

modelBuilder.Entity<Voyage>().HasKey<VoyageNumber>(k => k.VoyageNumber);

物业'VoyageNumber'不可能   用作实体的关键属性   'Domain.Model.Voyages.Voyage'因为   属性类型不是有效键   类型。只有标量类型,字符串和   byte []是支持的键类型。

当我尝试这个时:

modelBuilder.Entity<Voyage>().HasKey<string>(k => k.VoyageNumber.Id);

属性表达式'k =>   k.VoyageNumber.Id'无效。该   表达应该代表一个   property:C#:'t => t.MyProperty'

我是否真的要废弃我的VoyageNumber并用原始类型替换它?


9005
2018-04-02 10:23


起源

使用它时的异常消息是什么:modelBuilder.Entity <Voyage>()。HasKey <VoyageNumber>(k => k.VoyageNumber); - tpeczek
使用异常消息更新了问题。 - hoetz
在EF 6.1.3中仍然如此 - Tim Abell


答案:


这是限制。关键成员可以只是实体中的标量属性。复杂类型表示为不支持的复杂属性。


14
2018-04-02 11:43



太可惜了,我想我会先放弃Code,因为我不愿意放弃主键的封装。 - hoetz
我不清楚。这是实体框架的限制。不仅是代码的局限性。 - Ladislav Mrnka
这在EF6中仍然如此吗?我在原始问题中记录了相同的错误,因此我假设没有任何改变,但希望添加一些我缺少的配置选项。 - sellmeadog


对于隔离类,您可以通过向执行a的DbContext添加“get”方法来执行只读变通方法 SqlQuery<> 并在内部将表映射到类(以老式的方式)。

我在这里编写了一个最小的测试用例: https://github.com/timabell/ef-complex-pk

例如

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
            });
    }
}

0
2018-04-08 10:38





我们可以用下面的方法来解决它。希望它有用。

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;
    }
}

在dbContext中:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<TestPaperResult>()
                .Ignore(t => t.Id)
                .HasKey(t => new {t.TestPaperId, t.UserId});
 }

在存储库中:

 public Task<TestPaperResult> FindTestPaperResultAsync(TestPaperResultId id)
 {
     return GetByKeyAsync<TestPaperResult>(id.TestPaperId, id.UserId);
 }

0
2018-06-13 10:25