【问题标题】:EF Core - Create composite unique index with a value object and a parent typeEF Core - 使用值对象和父类型创建复合唯一索引
【发布时间】:2022-11-04 11:54:10
【问题描述】:

我有一个具有 ExternalSystemName 值对象和 Deployment 父类型的实体,它是另一个实体。模型的重要部分如下所示:

public sealed class ExternalSystem : Entity
{
    public ExternalSystemName Name { get; private set; }

    public Deployment Deployment { get; private set; }
}

此实体的唯一性由部署 ID(存储在部署实体类中)和名称(即 ExternalSystemName 值对象的值)的组合确定。换句话说,一个部署不能有两个同名的外部系统。

尝试使用 IEntityTypeConfiguration 实现设置此组合唯一索引时遇到问题:

internal sealed class ExternalSystemsConfiguration : 
IEntityTypeConfiguration<ExternalSystem>
{
    public void Configure(EntityTypeBuilder<ExternalSystem> builder)
    {
        builder.ToTable("TblExternalSystems");

        builder.OwnsOne(e => e.Name, navigationBuilder =>
        {
            navigationBuilder.Property(e => e.Value)
            .HasColumnName("Name");
        });

        builder.HasIndex(e => new { e.Name, e.Deployment }).IsUnique();
    }
}

运行我的 API 时出现此异常:

System.InvalidOperationException: ''Name' cannot be used as a property on entity type 'ExternalSystem' because it is configured as a navigation.'

我尝试将索引指向 e.Name.Value ,但出现此错误:

System.ArgumentException: 'The expression 'e => new <>f__AnonymousType0`2(Value = e.Name.Value, Deployment = e.Deployment)' is not a valid member access expression. The expression should represent a simple property or field access: 't => t.MyProperty'. When specifying multiple properties or fields, use an anonymous type: 't => new { t.MyProperty, t.MyField }'. (Parameter 'memberAccessExpression')'

我还在其中一个属性上尝试了唯一索引,但无论如何我都会收到导航错误。我担心我已经知道答案,但这是否意味着 EF Core 仅支持非实体、非 valueObject 类型的列上的索引?这是否意味着我的模型需要一个代表部署 ID 的 Guid 属性而不是部署本身?

更新

我了解到 EF Core 可以很好地处理引用/原始对。考虑到这一点,我的 ExternalSystem 实体现在可以同时拥有这两个属性:

public Deployment Deployment { get; private set; }

public Guid DeploymentId { get; private set; }

该 Guid 属性不是构造函数的一部分,因为它们最终获得相同的列名,所以一切正常。我现在可以将其添加到该实体的配置中,并且索引已正确创建:

builder.HasIndex(e => new { e.DeploymentId}).IsUnique();

我现在的问题是值对象。使用相同的方法,我想我可以做这样的事情吗?

public ExternalSystemName NameV { get; private set; }

public string Name { get; private set; }

我必须重命名值对象属性,因为它们显然不能共享相同的名称。这与实体类型无关,因为 EF Core 知道首先将“Id”添加到列名。通过此设置,EF Core 正在复制列。一个具有名称“Name”,另一个具有“ExternalSystem_Name”。显然,其他一切都失败了,因为该列不接受空值。为什么会这样?

【问题讨论】:

  • 将属性 NameIdDeploymentId 添加到 ExternalSystem 并在这些属性上添加索引。
  • 那么这些 Id 属性可以与关联的实体类型并行存在并与底层数据库一起使用吗?
  • 是的,底层数据库应该已经有这些列,因为 FK 和 EF 知道如何处理引用/原始属性对(又名外键关联)。
  • 这适用于实体类型,但我不确定如何以相同的方法处理值对象。我会更新我原来的帖子。

标签: c# entity-framework-core unique-constraint value-objects


【解决方案1】:

您需要使用 Fluent api 手动将键定义为外键。

builder.Entity<ExternalSystem>()
       .HasOne(g => g.NameV)
       .WithMany()
       .HasForeignKey(j => j.Name);

【讨论】:

    猜你喜欢
    • 2017-04-07
    • 2017-01-11
    • 2020-12-27
    • 2017-11-16
    • 2016-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多