Entity Framework 5 を使用して永続化される POCO ドメイン エンティティがあります。それらは、リポジトリ パターンを使用して DbContext から取得され、UoW パターンを介して RESTful MVC WebApi アプリケーションに公開されます。POCO エンティティはプロキシであり、遅延ロードされます。
エンティティをクライアントに送信する前に、エンティティを DTO に変換しています。これを行うために Automapper を使用していますが、Automapper がプロキシ POCO を DTO にマッピングし、ナビゲーション プロパティをそのまま維持することで問題なく動作しているようです。これには次のマッピングを使用しています。
Mapper.CreateMap<Client, ClientDto>();
ドメイン/DTO オブジェクトの例:
[Serializable]
public class Client : IEntity
{
public int Id { get; set; }
[Required, MaxLength(100)]
public virtual string Name { get; set; }
public virtual ICollection<ClientLocation> ClientLocations { get; set; }
public virtual ICollection<ComplianceRequirement> DefaultComplianceRequirements { get; set; }
public virtual ICollection<Note> Notes { get; set; }
}
public class ClientDto : DtoBase
{
public int Id { get; set; }
[Required, MaxLength(100)]
public string Name { get; set; }
public ICollection<ClientLocation> ClientLocations { get; set; }
public ICollection<ComplianceRequirementDto> DefaultComplianceRequirements { get; set; }
public ICollection<Note> Notes { get; set; }
}
今、ネットワークから送り返された DTO を使用してコンテキストを更新しようとしています。ナビゲーション プロパティ/関連エンティティを適切に機能させるのに特定の問題があります。私が使用しているこのマッピングは次のとおりです。
Mapper.CreateMap<ClientDto, Client>()
.ConstructUsing((Func<ClientDto, Client>)(c => clientUow.Get(c.Id)));
上記の clientUow.Get() は DbContext.Set.Find() を参照するため、追跡されたプロキシ POCO オブジェクトを EF から取得しています (これには、プロキシとしても関連するすべてのエンティティが含まれています)。
私のコントローラーメソッドでは、次のことを行っています。
var client = Mapper.Map<ClientDto, Client>(clientDto);
uow.Update(client);
クライアントはプロキシ POCO オブジェクトとして正常にマップされますが、関連するエンティティ/ナビゲーション プロパティは、DTO からコピーされたプロパティ値を持つ新しい (非プロキシ) POCO エンティティに置き換えられます。
上記の uow.Update() は基本的に、私が持っている持続ロジックを実行する関数を指します:
_context.Entry<T>(entity).State = System.Data.EntityState.Modified;
_context.SaveChanges();
上記は、関連するものは言うまでもなく、エンティティを永続化しても永続しません。マッピングのバリエーションと、デタッチ/状態を使用して永続化するさまざまな方法を試しましたが、常に「同じキーを持つオブジェクトが ObjectStateManager に既に存在します」という例外が発生します。
私は無数の他のスレッドを見てきましたが、Automapper ですべてを動作させることはできません。コンテキストからプロキシ オブジェクトを取得し、DTO からそれらを更新するプロパティを手動で調べることができますが、Automapper を使用してドメイン -> DTO をマップしています。私のドメイン オブジェクトにかなり似ています。
同時に更新する必要があるナビゲーション プロパティを持つドメイン オブジェクト/DTO を使用して、EF で Automapper を処理する教科書的な方法はありますか?
アップデート:
var originalEntity = _entities.Find(entity.Id);
_context.Entry<T>(originalEntity).State = System.Data.EntityState.Detached;
_context.Entry<T>(entity).State = System.Data.EntityState.Modified;
上記の永続化ロジックは、コンテキスト内の「ルート」EF プロキシ オブジェクトを更新しますが、関連するエンティティは更新されません。これは、それらが EF プロキシ オブジェクトではなく、単純なドメイン オブジェクトにマップされていることが原因であると推測しています。助けていただければ幸いです。
更新: 私が達成しようとしていることは、現在のバージョンの EF(5) を使用して実際には不可能であり、これは EF のコア制限であり、Automapper とは関係がないようです:
手動に戻ったと思います。これが同じことを考えている他の誰かに役立つことを願っています。