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は2回置き換えられます。同じエンティティは、savechangesの前にありません。 – user2963570

+0

おそらく、事前にロードしてから、盲目的に追加するのではなく、変更を加えてマージする必要があります。 –

答えて

2

問題は自己参照ではなく、述べたように同じPKで異なるDocumentTypeRetractRelationオブジェクトを生成する多対多のコレクションの変更を適用します例外メッセージにあります。

EFコアで現在の正しい方法は、その後、(元の値が含まれています)existingDocumentRetractDocumentTypesがロードされていることを確認し、既存または作成新しいDocumentTypeRetractRelationオブジェクトを使用してのいずれかの方法で変更をマージすることです。

// 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(); 

これは両方とも、追加、削除と変わらない関係を扱うことになると、次のコード

foreach (var retractDocumentTypeId in documentTypeUpdateDto.RetractDocumentTypeIds) 
{ 
    existingDocument.RetractDocumentTypes.Add(new DocumentTypeRetractRelation() 
    { 
     DocumentTypeId = existingDocument.Id, 
     RetractDocumentTypeId = retractDocumentTypeId 
    }); 
} 

を交換してください。 DocumentTypesと似たようなことができます。

実際にお使いのモデルを見て、上記のコードはコレクションのためのものである必要があります(Idと組み合わせて、DocumentTypesのコレクションコンテンツを構成しているため)。したがって、RetractDocumentTypesDocumentTypesに置き換えてください。

関連する問題