EF4.1 Code First 复杂类型作为主键

发布于 2024-10-29 13:27:22 字数 1016 浏览 1 评论 0原文

我目前正在尝试使用 Entity Framework 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' 无效。这 表达式应该代表一个 属性:C#: 't => t.MyProperty'

我真的必须丢弃我的 VoyageNumber 并将其替换为原始类型吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

自在安然 2024-11-05 13:27:22

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

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.

Oo萌小芽oO 2024-11-05 13:27:22

我们可以通过下面的方法来解决。希望它有帮助。

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

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);
 }
傲娇萝莉攻 2024-11-05 13:27:22

对于隔离类,您可以通过向 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
            });
    }
}

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
            });
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文