c# - 该属性是键的一部分,因此不能修改或标记为已修改(ForeignKey 不是键)

标签 c# entity-framework entity-framework-core ef-core-6.0

我有两个没有键的关系的实体,当我想编辑人员中的人员代码字段时,向我显示此错误。 '属性'Personnel.PersonnelCode' 是键的一部分,因此无法修改或标记为已修改。要更改具有标识外键的现有实体的主体,首先删除依赖项并调用“SaveChanges”,然后将依赖项与新主体相关联。“ EnrolNumberPersonnelNum 表也没有与我的表中更改的人事记录有关系的记录

人员类

public class Personnel : BaseEntity, IBaseEntityTypeConfiguration<Personnel>
    {
        public Personnel()
        {
            EnrolNumberPersonnelNums = new HashSet<EnrolNumberPersonnelNum>();
        }
        [Key]
        public int PersonnelId { get; set; }
        public string PersonnelCode { get; set; }
        public virtual ICollection<EnrolNumberPersonnelNum> EnrolNumberPersonnelNums { get; set; }

        public void Map(EntityTypeBuilder<Personnel> builder)
        {
            builder.ToTable("Personnel", "HR");

            builder.Property(e => e.PersonnelCode).HasMaxLength(50);
        }
    }

EnrolNumberPersonnelNum 类

 public class EnrolNumberPersonnelNum : BaseEntity, IBaseEntityTypeConfiguration<EnrolNumberPersonnelNum>
    {
        public EnrolNumberPersonnelNum()
        {
        }
        [Key]
        public int EnrolNumberPersonnelNumId { get; set; }
        public string PersonnelCode { get; set; }
        public virtual Personnel Personnel { get; set; }
     
        public void Map(EntityTypeBuilder<EnrolNumberPersonnelNum> builder)
        {
            builder.ToTable("EnrolNumberPersonnelNum", "HR");

            builder.Property(e => e.PersonnelCode)
                .HasMaxLength(50);

            builder.HasOne(c => c.Personnel).WithMany(c => c.EnrolNumberPersonnelNums)
                .HasForeignKey(c => c.PersonnelCode).HasPrincipalKey(c => c.PersonnelCode)
                .OnDelete(DeleteBehavior.ClientNoAction)
                .HasConstraintName($"FK_{nameof(EnrolNumberPersonnelNum)}_{nameof(Personnel)}_{nameof(PersonnelCode)}");
        }
    }

在人事实体​​中编辑人事代码时报错 并且 EnrolNumberPersonnelNum 表为空。

最佳答案

HasPrincipalKey(c => c.PersonnelCode) 在这里

builder.HasOne(c => c.Personnel).WithMany(c => c.EnrolNumberPersonnelNums)
    .HasForeignKey(c => c.PersonnelCode).HasPrincipalKey(c => c.PersonnelCode)
    .OnDelete(DeleteBehavior.ClientNoAction)
    .HasConstraintName($"FK_{nameof(EnrolNumberPersonnelNum)}_{nameof(Personnel)}_{nameof(PersonnelCode)}");

Personnel 实体的属性 PersonnelCode 标记为 alternate key :

An alternate key serves as an alternate unique identifier for each entity instance in addition to the primary key; it can be used as the target of a relationship. When using a relational database this maps to the concept of a unique index/constraint on the alternate key column(s) and one or more foreign key constraints that reference the column(s).

并且在 EF Core 中,所有类型的键(主键和备用键)都是只读,即 EF Core 不允许更新它们(需要并且只能为新实体提供)。这基本上就是错误消息一开始告诉你的内容

The property 'Personnel.PersonnelCode' is part of a key and so cannot be modified or marked as modified.

话虽如此,如果您需要该属性可编辑,目前还没有针对此类模型的解决方案。错误信息中的建议

To change the principal of an existing entity with an identifying foreign key, first delete the dependent and invoke 'SaveChanges', and then associate the dependent with the new principal.

似乎不可行,因为显然您不能删除受抚养人(EnrolNumberPersonnelNums 在您的情况下),然后将他们与新的 parent 相关联(因为他们已被删除)。最终你可以尝试将它们加载到内存中,然后调用 RemoveRange,修改父键,然后 SaveChanges,然后更新缓存的子实例的 PersonnelCode ,调用 AddRange,然后调用 SaveChanges。看起来不可靠/容易出错,但值得一试。

如果允许修改数据库,最好从 EnrolNumberPersonnelNum 中删除 PersonnelCode 并创建和使用绑定(bind)到的常规 FK int PersonnelId 人员的PK。这样您就可以删除备用键(并在需要时添加唯一约束),如文档中所述

Tip

If you just want to enforce uniqueness on a column, define a unique index rather than an alternate key (see Indexes). In EF, alternate keys are read-only and provide additional semantics over unique indexes because they can be used as the target of a foreign key.

这将允许将 PersonelPersonnelCode 更新为任何其他属性。

关于c# - 该属性是键的一部分,因此不能修改或标记为已修改(ForeignKey 不是键),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73704497/

相关文章:

c# - 在 Linq-to-SQL 中映射 UDF 有任何灵活性吗?

c# - 如果同时执行多个插入查询时发生错误,如何回滚表

entity-framework - 导入存储过程后无法编译项目

entity-framework - 如何正确使用 EFCore 和 SignalR Core(避免缓存实体)

c# - XUnit 测试 - InMemory 与真实数据库

c# - 将具有结构数组的结构从 C# 传递到 C++

c# - Linux 上的单声道 : mkbundle does not find shared libraries

c# - 在 Entity Framework 中,如何在保存之前调用实体上的方法

c# - MediatR 和 SimpleInjector 的依赖范围问题

c# - Entity Framework Core 忽略 .Include(..) 而没有 .ToList(..) 间接