I have two entities with a relationship without a key, when I want to edit the personnel code field in Personnel, this error is displayed to me.
'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.'
The EnrolNumberPersonnelNum table also does not have a record that has a relationship with the changed personnel record in my table
personnel class
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 class
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)}");
}
}
Error message when I want to edit personnel code in personnel entity and EnrolNumberPersonnelNum table is empty .
CodePudding user response:
HasPrincipalKey(c => c.PersonnelCode)
here
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)}");
marks the property PersonnelCode
of the Personnel
entity as 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).
And in EF Core all type of keys (primary and alternate) are read only, i.e. EF Core does not allow updating them (are required and can be provided only for new entities). This is basically what the error message is telling you at the beginning
The property 'Personnel.PersonnelCode' is part of a key and so cannot be modified or marked as modified.
With that being said, there is no solution so far for such type of model, if you need that property editable. The suggestion in the error message
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.
doesn't seem viable, since obviously you cannot delete dependents (EnrolNumberPersonnelNums
in you case) and then associate them with a new parent (since they are deleted). Eventually you can try loading them in memory, then call RemoveRange
, modify the parent key, then SaveChanges
, then update PersonnelCode
of the cached children instances, call AddRange
followed by SaveChanges
. Looks unreliable/error prone, but worth trying.
If you are allowed to modify the database, better remove the PersonnelCode
from EnrolNumberPersonnelNum
and create and use regular FK int PersonnelId
bound to the PK of the Personnel
. This way you can remove the alternate key (and add just unique constraint if needed) as mentioned in the documentation
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.
That will allow updating the PersonnelCode
of Personel
as any other property.