首页 > 解决方案 > EF core 3.1 - 实体和拥有类型的公用表

问题描述

我试图在我的项目中实现 DDD 方法,但意识到我的聚合太大,并试图最大限度地减少从数据库加载的数据量。我有一个聚合订单,在某些操作期间它依赖于另一个聚合公司。要执行RefreshOrderNumber()操作,我需要来自 Company 实体的三个属性,并且对 **Company 的其他字段完全不感兴趣。所以,我想到了为 Order - 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实体相同的表,因此在通过存储库加载 Order 聚合期间数据始终是实际的。所以我对 Order 聚合有这个配置:

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 核心以这种方式工作?

标签: c#asp.netentity-frameworkdomain-driven-design

解决方案


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

他们提供了一个示例,其中包含两个映射到同一张表的实体

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构建为拥有类型是错误的,因为拥有类型意味着拥有类型与所有者之间的关系。在我的场景中,这将导致Company表将具有OrderId字段的情况,这至少是不正确的。通过 HasOne() 配置 OrderCompanyInfo 实体非常适合我


推荐阅读