实体类型的属性是键的一部分,因此不能修改或标记为已修改

本文关键字:修改 不能 记为 属性 类型 实体 一部分 | 更新日期: 2023-09-27 18:33:55

我将Entity Framework 7.0.0-rc1-final与SQL 2014 LocalDB一起使用(代码优先(。我有模型类:

public class UnitGroup {
    public int UnitGroupId { get; private set; }
    public string Name { get; set; }
    public ObservableCollection<Unit> UnitSet { get; set; }
    public UnitGroup() {
        UnitSet = new ObservableCollection<Unit>();
    }
}

我使用此委托进行流畅配置:

Action<EntityTypeBuilder<UnitGroup>> UnitGroupConfig = delegate (EntityTypeBuilder<UnitGroup> e) {
        e.Property(p => p.Name).IsVarchar(25).IsRequired();
        e.HasAlternateKey(p => p.Name);
    };

IsVarchar(( 是我的扩展方法:

public static PropertyBuilder IsVarchar(this PropertyBuilder<string> propertyBuilder, int maxLength) {
        return propertyBuilder.HasColumnType($"varchar({maxLength})");
    }

然后我像这样使用它:

protected override void OnModelCreating(ModelBuilder modelBuilder) {    
        modelBuilder.Entity<UnitGroup>(e => UnitGroupConfig(e));
}

这是此表的迁移代码:

migrationBuilder.CreateTable(
            name: "UnitGroup",
            columns: table => new
            {
                UnitGroupId = table.Column<int>(nullable: false)
                    .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                Name = table.Column<string>(type: "varchar(25)", nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_UnitGroup", x => x.UnitGroupId);
                table.UniqueConstraint("AK_UnitGroup_Name", x => x.Name);
            });

迁移后,我的数据库:单位组表中有表

我需要将 EF 封装在我的棱镜数据模块中。我有一个课程:

public class DataService : IDataService {
private DataContext context;
public DataService() {
    context = new DataContext();
}
public IQueryable<T> GetAsTracking<T>(params Expression<Func<T, object>>[] includes) where T : class {
    return includes.Aggregate(context.Set<T>().AsTracking(), (source, expression) => {
        if (expression.Body is MemberExpression) {
            return source.Include(expression);
        }
        return source;
    });
}
public int SaveChanges() {
    return context.SaveChanges();
}

}

最后,我尝试运行这样的代码:

var ds = new DataService();
var ug = ds.GetAsTracking<UnitGroup>().First();
ug.Name="new value";
ds.SaveChanges();

并收到此错误:

实体类型"UnitGroup"上的属性"名称"是键的一部分,因此 不能修改或标记为已修改。

我在这里发现了类似的问题。这是一直编辑主键的问题。我检查了所有描述的部分两次。属性名称不是主键的一部分,而是唯一键的一部分。当我使用 EF6 时,我在部分迁移类中有代码:

CreateIndex("UnitGroup", "Name", unique: true);

这是创建相同的唯一键,我能够编辑名称。为什么现在在 EF7 中不可能?

实体类型的属性是键的一部分,因此不能修改或标记为已修改

多亏了Rowan Miller,我解决了这个问题。他说:

在 EF Core 中,备用密钥旨在用作 关系(即将有一个指向它的外键(。 目前 EF 不支持更改值。

如果我想要属性的唯一索引,那么我必须使用以下代码:

modelBuilder.Entity<UnitGroup>().HasIndex(u => u.Name).IsUnique();

我在 EF6 中得到了相同的异常,让我把我的解决方案放在这里。

就我而言,这很复杂,最后我找到了原因,首先我有两个 DbSet:

var listTableA = dbContext.Set<TableA>();
var listTableB = dbContext.Set<TableB>();
然后,

表A项的主键是修改,然后我RemoveRange表B,我得到了这个解释:

var itemA = listTableA.First();
//Id property is primary key of TableA
itemA.Id = 123;
// ... omit some code in the middle ... 
var itemsToDel = listTableB.Where(t=>t.CreateTime > "20180101");
// Exception throw here 
listableB.RemoveRange(itemsToDel); 

所以就我而言,问题并不是真正发生在listableB.RemoveRange,而是由修改 TableA 的主键itemA.Id = 123;引起的。

最后我避免修改tableA的主键,使用其他替代方式,问题就解决了。