在 EntityFramworkCore.InMemory 提供商中添加 ID = 0 的实体时出现问题
Problem adding entity with Id = 0 in EntityFramworkCore.InMemory provider
以下代码抛出异常:
System.InvalidOperationException: The instance of entity type
'DimEntity' cannot be tracked because another instance with the same
key value for {'EntityEntityId'} is already being tracked. When
attaching existing entities, ensure that only one entity instance with
a given key value is attached
var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
optionsBuilder.UseInMemoryDatabase("Test");
using (var dbContext = new MyDbContext(optionsBuilder.Options))
{
//when I comment this line, the rest works file
dbContext.DimEntity.Add(new DimEntity { EntityEntityId = 0, EntityKey = "Uknown" });
//otherwise this line throws the exception
dbContext.DimEntity.Add(new DimEntity { EntityEntityId = 1, EntityKey = "DFS Region" });
= "Europe Region" });
dbContext.DimEntity.Add(new DimEntity { EntityEntityId = 2, EntityKey = "Europe Region" });
}
为什么?
其他详细信息:
public partial class MyDbContext : DbContext
{
public MyDbContext (DbContextOptions<MyDbContext> options)
: base(options)
{
}
public virtual DbSet<DimEntity> DimEntity { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DimEntity>(entity =>
{
entity.HasKey(e => e.EntityEntityId);
entity.ToTable("DimEntity", "mm");
entity.Property(e => e.EntityEntityId).HasColumnName("Entity_EntityID");
});
}
}
public partial class DimEntity
{
public int EntityEntityId { get; set; }
public string EntityKey { get; set; }
}
它不是特定于内存提供程序的。按照约定 int
PK 被视为自动递增 (SqlServer identity
),因此问题类似于向自动递增列添加显式值时的问题。
如果将 new DimEntity { EntityEntityId = 0, ... }
保存在变量中,您会看到 Add
之后 EntityEntityId
的值将为 1(因为当 PK 值为默认值时( 0 表示 int
),执行 value generation on add)。
但是当您添加具有非默认 int
PK 的实体时,不会生成任何值并且会为 EntityEntityId = 1
抛出异常,因为它已经存在 - 为您创建的第一个实体生成的值先添加。
一般来说,如果您不想生成 PK 值,您应该在 OnModelCreating
:
中选择加入
entity.Property(e => e.EntityEntityId)
.HasColumnName("Entity_EntityID")
.ValueGeneratedNever(); // <--
如果您确定在创建实体时(即在您的业务逻辑和测试代码中)总是明确地为实体的 ID 字段赋值,只需用 属性 注释=21=] 设置为 DatabaseGeneratedOption.None
:
public partial class DimEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int EntityEntityId { get; set; }
public string EntityKey { get; set; }
}
三种可能DatabaseGeneratedOption
values None
, Identity
, Computed
correspond to the fluent methods ValueGeneratedNever
, ValueGeneratedOnAdd
, ValueGeneratedOnAddOrUpdate
. The fluent syntax also offers ValueGeneratedOnUpdate
看似多余,但如果你需要它就在那里。
以下代码抛出异常:
System.InvalidOperationException: The instance of entity type 'DimEntity' cannot be tracked because another instance with the same key value for {'EntityEntityId'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached
var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
optionsBuilder.UseInMemoryDatabase("Test");
using (var dbContext = new MyDbContext(optionsBuilder.Options))
{
//when I comment this line, the rest works file
dbContext.DimEntity.Add(new DimEntity { EntityEntityId = 0, EntityKey = "Uknown" });
//otherwise this line throws the exception
dbContext.DimEntity.Add(new DimEntity { EntityEntityId = 1, EntityKey = "DFS Region" });
= "Europe Region" });
dbContext.DimEntity.Add(new DimEntity { EntityEntityId = 2, EntityKey = "Europe Region" });
}
为什么?
其他详细信息:
public partial class MyDbContext : DbContext
{
public MyDbContext (DbContextOptions<MyDbContext> options)
: base(options)
{
}
public virtual DbSet<DimEntity> DimEntity { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DimEntity>(entity =>
{
entity.HasKey(e => e.EntityEntityId);
entity.ToTable("DimEntity", "mm");
entity.Property(e => e.EntityEntityId).HasColumnName("Entity_EntityID");
});
}
}
public partial class DimEntity
{
public int EntityEntityId { get; set; }
public string EntityKey { get; set; }
}
它不是特定于内存提供程序的。按照约定 int
PK 被视为自动递增 (SqlServer identity
),因此问题类似于向自动递增列添加显式值时的问题。
如果将 new DimEntity { EntityEntityId = 0, ... }
保存在变量中,您会看到 Add
之后 EntityEntityId
的值将为 1(因为当 PK 值为默认值时( 0 表示 int
),执行 value generation on add)。
但是当您添加具有非默认 int
PK 的实体时,不会生成任何值并且会为 EntityEntityId = 1
抛出异常,因为它已经存在 - 为您创建的第一个实体生成的值先添加。
一般来说,如果您不想生成 PK 值,您应该在 OnModelCreating
:
entity.Property(e => e.EntityEntityId)
.HasColumnName("Entity_EntityID")
.ValueGeneratedNever(); // <--
如果您确定在创建实体时(即在您的业务逻辑和测试代码中)总是明确地为实体的 ID 字段赋值,只需用 属性 注释=21=] 设置为 DatabaseGeneratedOption.None
:
public partial class DimEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int EntityEntityId { get; set; }
public string EntityKey { get; set; }
}
三种可能DatabaseGeneratedOption
values None
, Identity
, Computed
correspond to the fluent methods ValueGeneratedNever
, ValueGeneratedOnAdd
, ValueGeneratedOnAddOrUpdate
. The fluent syntax also offers ValueGeneratedOnUpdate
看似多余,但如果你需要它就在那里。