【问题标题】:how to create index for value-object member using c# EF fluent api如何使用 c# EF fluent api 为值对象成员创建索引
【发布时间】:2021-11-18 18:34:48
【问题描述】:

我的实体包含名称为 IdCard 的值对象,如下所示:

public class UserProfile : BaseEntity<long>
{
  public byte Gender { get; private set; } = 0;

  public int? BirthDate { get; private set; }

  public IdCard IdCard { get; set; }
}

还有IdCard 这样的成员:

public class IdCard : ValueObject
    {
        public int? Type { get; set; }

        public string No { get; set; }
    }

我需要使用 EF fluent api 将 IdCard No 作为索引

类似的东西

builder.HasIndex(c => c.IdCard.No);

【问题讨论】:

  • 对域层和持久层 (EF) 使用相同的类是错误的方法。它将迫使您对域类的封装进行包含以用于持久性目的。将域类与持久性类分开是 DDD 的第一步。

标签: c# domain-driven-design value-objects


【解决方案1】:

查看来自 Microsoft 的 Implement value objects 和 Using Value Objects with Entity Framework Core 链接。这两个很有帮助。

您可以按如下方式创建UserProfileConfiguration 类:

public class UserProfileConfiguration : IEntityTypeConfiguration<UserProfile>
{
    public void Configure(EntityTypeBuilder<UserProfile> builder)
    {
        builder.HasKey(x => x.Id);
        builder.OwnsOne(x => x.IdCard);
        builder.HasIndex(x => x.No);
    }
}

然后,在您的DbContext 中的OnModelCreating 方法中应用它:

modelBuilder.ApplyConfiguration(new UserProfileConfiguration());

【讨论】:

  • Ardalas 解决方案是这样的builder.OwnsOne(p =&gt; p.AnimalType, p =&gt;{p.Property(pp=&gt;pp.Breed).HasColumnName("AnimalType_Breed").HasMaxLength(50);p.Property(pp =&gt;pp.Species).HasColumnName("AnimalType_Species").HasMaxLength(50);});,所以我们可以用同样的方式制作密钥。
  • 这是对OwnsOne() 方法的另一个覆盖,用于配置您的实体。他们都做同样的事情。在这种情况下,您可以使用buildAction 参数如下:builder.OwnsOne(x =&gt; x.Shipper, buildAction =&gt; { buildAction.HasIndex(x =&gt; x.Code); });
【解决方案2】:

您的IdCard 的广告构造函数将采用单个参数,在本例中为No。以下应该适用于值对象具有将存储在数据库中的单个字段时,因此 Type 不必存储,而是在 db fetch 之后计算。否则,这将必须存储为拥有的实体。 或者,您可以将 Type 和 No 一起存储在单个字段中,并为这些字段提供自定义转换器,但至少可以说这种解决方案不是最理想的。

在流畅的配置中,假设尝试:

modelBuilder.Entity<UserProfile>(builder =>
{
    builder.HasIndex(c => c.IdCard);
    builder.Property(p => p.IdCard)
        .HasConversion(id => id.No, value => new IdCard(value)); 
});

我不记得这是否可以在 EF 核心中正常工作 - 过去用于主键的转换器存在一些问题,但值得一试。

【讨论】:

  • 此代码 builder.HasIndex(c =&gt; c.IdCard); 将无法正常工作,因为它不是单个属性。
  • 我使用OwnsOne(x =&gt; x.IdCard) 修复了它,并成功设置了我的属性类型。
  • 我可以用同样的方式修复索引,但我不确定这是处理 Value-Object 的最佳方式。
  • 对于值对象,这是一种首选方式 - 在这种情况下,它是 UserProfile 的一部分,它不应该单独访问(拥有的类型不能通过 dbSet 访问),它应该是总是加载它的父级。
猜你喜欢
  • 2014-09-05
  • 1970-01-01
  • 2021-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 2022-11-04
  • 1970-01-01
相关资源
最近更新 更多