C# 实体框架代码第一个现有数据库集EntityState。在多对多上未更改
我有一个现有的数据库,我先用EntityFramework6代码编码。我有一个用于选择、插入和删除的多对多关系。我对EF在现有关系的多对多表中添加额外插入有问题 模式: DbContext:C# 实体框架代码第一个现有数据库集EntityState。在多对多上未更改,c#,entity-framework,entity-framework-6,C#,Entity Framework,Entity Framework 6,我有一个现有的数据库,我先用EntityFramework6代码编码。我有一个用于选择、插入和删除的多对多关系。我对EF在现有关系的多对多表中添加额外插入有问题 模式: DbContext: protected override void OnModelCreating(DbModelBuilder modelBuilder) { Database.SetInitializer<MainContext>(null); modelBuil
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<MainContext>(null);
modelBuilder.Entity<DocumentType>()
.HasMany(u => u.DocumentStatuses)
.WithMany()
.Map(m =>
{
m.MapLeftKey("DOCUMENT_TYPE_ID");
m.MapRightKey("DOCUMENT_STATUS_ID");
m.ToTable("DOCUMENT_TYPES_DOCUMENT_STATUSES");
});
base.OnModelCreating(modelBuilder);
}
包含以下内容的循环:
if (item.Id != null)
db.Entry(item).State = EntityState.Unchanged;
阻止添加新记录,但EF仍尝试将现有多对多记录的副本插入到“文档类型”“文档状态”中
单元测试:
[TestMethod()]
public void UpdateTest()
{
DocumentTypeRepository documentTypeRepository = new DocumentTypeRepository();
DocumentType type = NewDocumentType(true);
DocumentType typefromDb;
string updatedBy = "DocumentTypeRepositoryTests.UpdateTest";
bool actual;
type.IsActive = true;
type.TypeName = RandomValues.RandomString(18);
type.DocumentStatuses.Add(DocumentStatusRepositoryTests.NewDocumentStatus(true));
actual = documentTypeRepository.Update(type, updatedBy);
Assert.AreEqual(true, actual);
typefromDb = documentTypeRepository.GetById((int)type.Id);
Assert.AreEqual(type.DocumentStatuses.Count, typefromDb.DocumentStatuses.Count);
}
如何将多对多表设置为EntityState。当它已经存在时,将保持不变?尝试替换
db.DocumentTypes.Add((DocumentType)entity);
db.Entry(entity).State = EntityState.Modified;
与
当对分离的实体执行CRUD操作时,不使用DbSet操作而只操作实体状态条目更容易。至少,它会减少错误。这里需要注意两件事:
向上下文添加
实体时,该实体拥有的整个对象图将标记为已添加
1:n:1
关联,n
部分在代码中不可见)db.DocumentTypes.Add(entity);
使关联获得添加的状态,以及随后的
db.Entry(entity).State = EntityState.Modified;
不会再改变这个了
您必须确保现有的文档类型
的状态从未更改为已添加
,您可以通过检查其Id
值来执行此操作,这与检查文档状态
的操作相同
此外,您还必须更改设置文档状态的方式:
foreach (var item in entity.DocumentStatuses)
{
db.Entry(item).State = item.Id != null
? EntityState.Unchanged
: EntityState.Added;
}
我确实在上面有一行使用检查id的代码:if(entity.id==null)抛出新的InvalidOperationException(“DocumentTypeId在更新时不能为null”);我将其移除以保持示例更干净。有趣的是,我在您的示例中忽略了错误,但它没有保存添加到列表中的任何新状态,只是保留了旧状态。关键部分是删除。AddI在上面添加了我的单元测试,当我向列表添加新状态项并进行更新(使用新代码)时,它不会将新项添加到多对多表中。所以最后一个断言失败了,因为它只有第一个状态,而不是两个状态。@Josh Frank是对的,但其中涉及的内容比看上去的要多。我在回答中解释了这一点。一句话没用,这是有道理的。顺便说一句,强制转换是一个复制粘贴挂起,我有其他使用接口的对象,所以这就是为什么我有一个强制转换。所以问题在于Frank的更改不再试图向表插入重复的1:n:1关系。问题是,如果我将另一个DocumentStatus添加到DocumentType.DocumentStatus,然后调用此更新方法,它不会为新添加的DocumentStatus创建1:n:1记录。所以我们解决了一个问题,但又创造了一个新的问题。我也这么想并尝试了。但是如果你看一下我上面的单元测试,我并没有添加一个新的状态,而是添加了一个新的1:n:1与现有状态的关系。因此,项的EntityState状态将有一个Id,因此它将始终为EntityState。未更改,这是有意义的,因为它已经存在。我看不出其中到底发生了什么,但至少这是方向。它在我正在测试的简单多对多模式下工作。如果您从列表中删除一个项目并保存,我们会遇到相同类型的问题,它基本上不会删除1:n:1关系。您必须在DocumentType
及其状态附加到上下文后删除一个项目,否则,更改跟踪器将永远不会知道曾经有一个项目要删除。
db.DocumentTypes.Add(entity);
db.Entry(entity).State = EntityState.Modified;
foreach (var item in entity.DocumentStatuses)
{
db.Entry(item).State = item.Id != null
? EntityState.Unchanged
: EntityState.Added;
}