EFCore将2个实体映射到同一个表

时间:2018-04-23 17:26:29

标签: entity-framework-core

我正在尝试将DDD与EFCore一起使用,我正在努力寻找一种方法,将来自不同上下文的2个POCO映射到同一个表中。

我在UserContext中有一个User类,具有为我的应用程序创建新用户所需的所有属性。 我在OrderContext中有一个User类,在这个类中我只有Id和Email属性,因此在OrderContext中需要它才能工作。

所以我有这样的事情:

        modelBuilder.Entity<Domain.UserContext.User>(u =>
        {
            u.ToTable("User").HasKey(e => e.Id);
            u.OwnsOne(e => e.Name);
            u.OwnsOne(b => b.HomeAddress);
        });

        modelBuilder.Entity<Domain.OrderContext.User>(u =>
        {
            u.ToTable("User").HasKey(e => e.Id);
        });

        modelBuilder.Entity<Domain.OrderContext.Order>(p =>
        {
            p.ToTable("Order").HasKey(b => b.Id);
            p.HasOne(x => x.User); // this is OrderContext.User
        });

我似乎无法找到将两个User类映射到同一个表的方法。有办法吗?

Edit1:两个上下文都是有界的上下文DDD的概念,而不是DbContext。 我只需要将两个类作为同一个表进行maped。 Add-Migration命令返回一条消息,告诉我它不能将'OrderContext.User'映射到表'User',因为它已经映射到'UserContext.User'。

3 个答案:

答案 0 :(得分:6)

问题的主要原因是,EF Core无法弄清楚如何为2个不同的实体使用相同的表。映射中缺少数据,一旦填写完毕,它就会按预期工作。

首先,您需要定义它们之间的相互关系。使用相同的PK共享相同的表没有在服务器端定义外键,但两个实体之间仍然存在内在关系,这是一对一的并且使用PK作为FK。定义关系后,您将看到它工作正常,两个实体都映射到同一个表。 (就像拥有的实体如何映射到同一个表)。这可能不是你的情况的映射结束。从EF角度来看,它们仍然是2个不同的实体,除了Id(或PK属性)之外,它们将拥有自己的列来存储数据。但是,如果您在上下文中都有常见的列(例如您的方案中的Email),该怎么办?在这种情况下,您还需要为这些附加列提供映射。如果将它们显式映射到同一列,它们将开始在数据库中共享该列。整体而言,代码看起来像这样。

namespace UserContext
{
    public class User
    {
        public int Id { get; set; }
        public string Email { get; set; }
        // Other properties
    }
}

namespace OrderContext
{
    public class User
    {
        public int Id { get; set; }
        public string Email { get; set; }
    }
}

// In OnModelCreating method
modelBuilder.Entity<UserContext.User>(u =>
{
    u.ToTable("User");
    u.Property(e => e.Email).HasColumnName("Email");
    // Configuration for other properties
});

modelBuilder.Entity<OrderContext.User>(u =>
{
    u.ToTable("User");
    u.Property(e => e.Email).HasColumnName("Email");
    u.HasOne<UserContext.User>().WithOne().HasForeignKey<OrderContext.User>(e => e.Id);
});

上面的代码创建了包含共享列的单个表,并且应该按预期工作。如果需要,可以按照相同的配置在同一个表中添加更多实体。在这里,我使用来自User的{​​{1}}作为主要方面,但您可以使用任何一方。我的主要理由是,UserContext将是添加新用户时添加的实体。共享表的实体也不必是子集。但是会有一些列没有共享的其他属性。

答案 1 :(得分:3)

@Smit提供的解决方案应该可行,但它对于隔离的有界上下文并不理想,因为它们中的每一个都不会彼此意识到并且每个都在处理它自己的配置。

我通过为每个有界上下文添加单独的DbContexts解决了这个问题。这些上下文中的每一个都继承了基础DbContext,其中我有我的共享逻辑(如审计等),并且有界上下文中的每个DbContext都有自己的DbSets和Fluent Api配置。这样我就有了指向同一个表的实体,但来自不同的DbContexts。

答案 2 :(得分:1)

我自己正在看这个问题。我注意到,如果你为其中一个表指定了模式名称,那么EF就不会抱怨。 例如,在您的情况下:

{{1}}

当然,这不是一个完整的解决方案,甚至也不是一种解决方法,因为你不能超过两个提及&#34;用户&#34;表(即超过2个上下文)。

我也发现https://data.uservoice.com/forums/72025-entity-framework-core-feature-suggestions/suggestions/1872001-map-multiple-entities-to-same-table让我觉得这一般是不可能的。

关于一般的DDD

大多数消息来源表示,您的有界上下文不仅应该通过代码隔离,还应该通过数据隔离。理论上,这意味着您的User表应该在每个有界上下文中重复。这是理想的方式,但对于更简单的场景来说是不必要的复杂(imho),因为它涉及跨所有重复表的数据同步。