1

實體模型:EF核心 - 自引用多對多的關係

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我收到以下錯誤:

The instance of entity type 'DocumentTypeRetractRelation' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context.

+0

該異常表示重複的「DocumentTypeRetractRelation」**鍵**。檢查是否填充了「existingDocument」導航屬性。此外,使用'DbContext'的生命週期。 –

+0

他們是。在savechanges之後,id被get換成2倍於savechanges之前的情況。 – user2963570

+0

您可能需要預先加載它們,然後合併更改而不是盲目添加。 –

回答

2

的問題不是自我參照,但應用了許多一對多集合修改其產生不同DocumentTypeRetractRelation對象具有相同PK的聲明在異常消息中。

在EF核心目前正確的方法是,以確保existingDocumentRetractDocumentTypes加載(包括原始值),然後合併使用現有的或創建新的對象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替換爲DocumentTypes即可。