我有一个现有的数据库,我正在使用Entity Framework 6 Code First进行编码。我有一个多对多的关系,适用于选择,插入和删除。我在EF为现有关系的多对多表添加额外插入时遇到问题。
架构:
的DbContext:
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);
}
的DTO:
[Table("DOCUMENT_TYPES")]
public class DocumentType
{
[Key]
[Column("DOCUMENT_TYPE_ID")]
public int? Id { get; set; }
[Required]
[Column("TYPE_NAME")]
public string TypeName { get; set; }
[Required]
[Column("IS_ACTIVE")]
public bool IsActive { get; set; }
[Display(Name = "Updated By")]
[Column("LAST_UPDATED_BY")]
public string LastUpdatedBy { get; set; }
[Display(Name = "Updated Date")]
[Column("LAST_UPDATED_DATE")]
public DateTimeOffset? LastUpdatedDate { get; set; }
public virtual List<DocumentStatus> DocumentStatuses { get; set; }
public DocumentType()
{
DocumentStatuses = new List<DocumentStatus>();
}
}
[Table("DOCUMENT_STATUSES")]
public class DocumentStatus
{
[Key]
[Column("DOCUMENT_STATUS_ID")]
public int? Id { get; set; }
[Required]
[Column("STATUS_NAME")]
public string StatusName { get; set; }
[Required]
[Column("IS_COMPLETE")]
public bool IsComplete { get; set; }
[Required]
[Column("IS_ACTIVE")]
public bool IsActive { get; set; }
[Display(Name = "Updated By")]
[Column("LAST_UPDATED_BY")]
public string LastUpdatedBy { get; set; }
[Display(Name = "Updated Date")]
[Column("LAST_UPDATED_DATE")]
public DateTimeOffset? LastUpdatedDate { get; set; }
}
存储库更新:
public bool Update(DocumentType entity, string updatedBy)
{
DateTimeOffset updatedDateTime = DateTimeOffset.Now;
entity.LastUpdatedBy = updatedBy;
entity.LastUpdatedDate = updatedDateTime;
using (var db = new MainContext())
{
db.DocumentTypes.Add((DocumentType)entity);
db.Entry(entity).State = EntityState.Modified;
foreach (var item in entity.DocumentStatuses)
{
if (item.Id != null)
db.Entry(item).State = EntityState.Unchanged;
}
db.SaveChanges();
}
return true;
}
包含以下内容的循环:
if (item.Id != null)
db.Entry(item).State = EntityState.Unchanged;
阻止添加新记录,但EF仍尝试在DOCUMENT_TYPES_DOCUMENT_STATUSES中插入现有多对多记录的副本。
单元测试:
[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.Unchanged?
答案 0 :(得分:1)
尝试替换
db.DocumentTypes.Add((DocumentType)entity);
db.Entry(entity).State = EntityState.Modified;
与
db.Entry(entity).State = entity.Id == null
? EntityState.Added
: EntityState.Modified;
使用分离的实体执行CRUD操作时,更容易不使用DbSet操作并仅操纵实体状态条目。至少,它可以减少错误。
答案 1 :(得分:1)
这里有两件事需要注意:
当您将Add
实体添加到上下文时,该实体拥有的整个对象图标记为Added
。
在任何关联中,这也将协会标记为新的。但是,在1:n或1:1关联中,当其中一个结束的状态发生变化时,关联状态会发生变化,在多对多关联中,有一部分关联被隐藏,并且总是保持Added
。 (引擎盖下的多对多关联是1:n:1
关联,n
部分在您的代码中不可见。
所以这句话......
db.DocumentTypes.Add(entity);
导致关联获得Added
状态,以及随后的......
db.Entry(entity).State = EntityState.Modified;
不再对此进行更改。
您必须确保对于现有DocumentType
状态永远不会更改为Added
,您可以通过检查其Id
值来执行此操作,与DocumentStatus
相同1}}。
此外,您必须更改设置DocumentStatuses
的状态:
foreach (var item in entity.DocumentStatuses)
{
db.Entry(item).State = item.Id != null
? EntityState.Unchanged
: EntityState.Added;
}