EF 核心 3.1 - 实体和拥有类型的通用 table

EF core 3.1 - common table for entity and owned type

我正在尝试在我的项目中实施 DDD 方法,但意识到我的聚合太大,并试图尽量减少从数据库加载的数据量。我有一个聚合 Order,它在某些操作中依赖于另一个聚合 - Company。要执行 RefreshOrderNumber() 操作,我需要 Company 实体的三个属性,并且对 **Company 的其他字段完全不感兴趣。因此,我想到了为订单创建一个值类型 - OrderCompanyInfo 并将这些字段封装在其上

public class Company
{
   public Id {get;private set;}
   public string Name {get; private set;}
   public string Currency {get; private set;}
   public string DocumentPrefix {get; private set;}
   // other ~15 fields
}

public class OrderCompanyInfo : ValuableType
{
   private OrderCompanyInfo ()
   {

   }
  
   public long CompanyId {get; private set;}
   public string Name {get; private set;}
   public string Currency {get; private set;}
   public string DocumentPrefix {get; private set;}
  
  public static OrderCompanyInfo Create(Company company)
  {
     return OrderCompanyInfo {
       CompanyId = company.Id,
       Name = company.Name,
       Currency = company.Currency ,
       DocumentPrefix = company.DocumentPrefix 
     }

  }
}

public class Order
{

  private Order()
  {
     
  }

  public Order(OrderCompanyInfo companyInfo)
  {
    CompanyInfo = companyInfo; 
    AddLog();
  }

  public OrderNumberInfo OrderNumber {get; private set;}
  public OrderCompanyInfo CompanyInfo {get; private set;}

 

  public void DoSomethingImportant()
  {
    RefreshOrderNumber();
    AddLog();
  }

  private void AddLog()
  {
     //Add log entry using CompanyInfo.Name
  }

  private void RefreshOrderNumber()
  {
     //Create new OrderNumberInfo using OrderCompanyInfo.Currency and OrderCompanyInfo.DocumentPrefix 
  }
}

现在我正在努力使它与 EF 核心一起工作。基本上 OrderCompanyInfo 应该使用 OwnOne() 方法进行配置,并映射到与 Company[=29 相同的 table =] 实体有,因此数据在通过存储库加载订单聚合期间始终是实际的。所以我有这样的订单聚合配置:

public override void Configure(EntityTypeBuilder<Order> builder)
{
    builder.OwnsOne(x => x.InventoryOwnsCompanyProfile, opt =>
             {
                 opt.ToTable("Company"); 

                 opt.HasOne<Company>()
                    .WithOne()
                    .HasForeignKey<OrderCompanyInfo>(x => x.CompanyId);
             });
}

但是尝试这种方式给我一个错误:

Cannot use table 'dbo.Company' for entity type 'OrderCompanyInfo ' since it is being used for entity type 'Company' and there is no relationship between their primary keys.

有没有办法让 EF 核心以这种方式工作?

好的,答案已在 GitHub 社区中找到。 https://github.com/dotnet/efcore/issues/13162#issuecomment-417411405

他们提供了一个示例,其中两个实体映射到同一个 table

namespace One
{
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

namespace Two
{
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime Birthday { get; set; }
    }
}

public class BloggingContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0");

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<One.Person>(b =>
        {
            b.HasOne<Two.Person>().WithOne().HasForeignKey<Two.Person>(e => e.Id);
            b.ToTable("People");
            b.Property(e => e.Name).HasColumnName(nameof(One.Person.Name));
        });

        builder.Entity<Two.Person>(b =>
        {
            b.ToTable("People");
            b.Property(e => e.Name).HasColumnName(nameof(Two.Person.Name));
        });
    }
}

我试图将 OrderCompanyInfo 构建为 Owned 类型是错误的,因为拥有的类型意味着从拥有的类型到所有者的关系。在我的场景中,这将导致 Company table 将具有 OrderId 字段的情况,这至少是不正确的。通过 HasOne() 配置 OrderCompanyInfo 实体非常适合我