实体模型:
public class DocumentType : CodeBase
{
[Required]
[MaxLength(100)]
public string Name { get; set; }
public TimeSpan? Productiontime { get; set; }
public bool IsDeliverable { get; set; }
public virtual ICollection<DocumentTypeRetractRelation> DocumentTypes { get; set; }
public virtual ICollection<DocumentTypeRetractRelation> RetractDocumentTypes { get; set; }
}
关系模型:
/// <summary>
/// Relationship between document types showing which documenttypes can
/// retracted when delivering a new document.
/// </summary>
[Table("DocumentTypeRetractRelation")]
public class DocumentTypeRetractRelation
{
public int DocumentTypeId { get; set; }
public virtual DocumentType DocumentType { get; set; }
public int RetractDocumentTypeId { get; set; }
public virtual DocumentType RetractDocumentType { get; set; }
}
模型构建器:
modelBuilder.Entity<DocumentTypeRetractRelation>().HasKey(x => new { x.DocumentTypeId, x.RetractDocumentTypeId });
modelBuilder.Entity<DocumentTypeRetractRelation>()
.HasOne(x => x.DocumentType)
.WithMany(x => x.DocumentTypes)
.HasForeignKey(x => x.DocumentTypeId);
modelBuilder.Entity<DocumentTypeRetractRelation>()
.HasOne(x => x.RetractDocumentType)
.WithMany(x => x.RetractDocumentTypes)
.HasForeignKey(x => x.RetractDocumentTypeId);
更新作家:
public async Task<DocumentType> UpdateAsync(DocumentTypeUpdateDto documentTypeUpdateDto)
{
using (IUnitOfWork uow = UowProvider.CreateUnitOfWork<EntityContext>())
{
var documentTypeRepo = uow.GetCustomRepository<IDocumentTypeRepository>();
var existingDocument = await documentTypeRepo.GetAsync(documentTypeUpdateDto.Id);
if (existingDocument == null)
throw new EntityNotFoundException("DocumentType", existingDocument.Id);
foreach (var retractDocumentTypeId in documentTypeUpdateDto.RetractDocumentTypeIds)
{
existingDocument.RetractDocumentTypes.Add(new DocumentTypeRetractRelation()
{
DocumentTypeId = existingDocument.Id,
RetractDocumentTypeId = retractDocumentTypeId
});
}
documentTypeRepo.Update(existingDocument);
await uow.SaveChangesAsync();
return existingDocument;
}
}
尝试更新existingDocument时,出现以下错误:
实体类型'DocumentTypeRetractRelation'的实例不能 跟踪,因为具有相同密钥的此类型的另一个实例是 已被跟踪。添加新实体时,对于大多数关键类型a 如果没有设置密钥,则将创建唯一的临时密钥值(即,如果 key属性被赋予其类型的默认值)。如果你 明确设置新实体的关键值,确保不这样做 与现有实体或为其他实体生成的临时值发生冲突 新实体。附加现有实体时,请确保只有一个实体 具有给定键值的实体实例附加到上下文。
答案 0 :(得分:2)
问题不在于自引用,而是应用多对多的集合修改,这些修改生成具有与异常消息中所述相同的PK的不同DocumentTypeRetractRelation
个对象。
EF Core中当前的正确方法是确保加载RetractDocumentTypes
existingDocument
(包含原始值),然后使用现有合并或创建新{{1}合并更改对象。
替换以下代码
DocumentTypeRetractRelation
与
foreach (var retractDocumentTypeId in documentTypeUpdateDto.RetractDocumentTypeIds)
{
existingDocument.RetractDocumentTypes.Add(new DocumentTypeRetractRelation()
{
DocumentTypeId = existingDocument.Id,
RetractDocumentTypeId = retractDocumentTypeId
});
}
这将处理添加,删除和未更改的关系。您可以执行与// existingDocument.RetractDocumentTypes should be loaded (either eager or explicit)
existingDocument.RetractDocumentTypes = (
from retractDocumentTypeId in documentTypeUpdateDto.RetractDocumentTypeIds
join existingRelation in existingDocument.RetractDocumentTypes
on retractDocumentTypeId equals existingRelation.RetractDocumentTypeId
into existingRelations
select existingRelations.FirstOrDefault() ?? new DocumentTypeRetractRelation()
{
DocumentTypeId = existingDocument.Id,
RetractDocumentTypeId = retractDocumentTypeId
}).ToList();
类似的操作。
实际上看一下你的模型,上面的代码应该是DocumentTypes
集合(因为你收到了DocumentTypes
,它与文档RetractDocumentTypeIds
结合形成Id
收集内容)。因此,只需将DocumentTypes
替换为RetractDocumentTypes
。