一般に、Automapper を使用して DTO データからエンティティをインフレートすることはお勧めできません。エンティティからビューモデル、webapimodels、または一般的な DTO にデータを渡すなど、反対方向に進むのに最適です。しかし、特に EntityFramework では、それをクライアントからドメインへの方向で使用すると、面倒になる可能性があります。
たとえば、ビューモデルにない 2 つのプロパティがエンティティにあるとしid
ますCreatedAt
。が例外をスローしないようにするには、プロパティの無視またはカスタム リゾルバーに加えて、呼び出しでAutoMapper.Mapper.AssertConfigurationIsValid()
これら 2 つのプロパティのカスタム リゾルバーを無視または使用する必要があることを意味します。最終的に、自動マッピングされるのは だけであり、そもそも automapper を使用する目的を無効にします。CreateMap
Departments
name
DTO をエンティティに変換するためのコードは、実際にはかなり簡潔です。正直なところ、私が変更する主な点は automapper の削除です。この場合、それは本当に必要ありません。
var reg = new Registration { name = dto.name }; // less code than with automapper
reg.Departments = new List<int>(dto.Departments)
.ConvertAll(input => Context.Departments.Find(input));
if(reg.Departments.Contains(null)) //a department provided does not exist in the database
return Request.CreateResponse(HttpStatusCode.BadRequest, "invalid department");
次のようなことを試してみたくなるかもしれません:
Mapper.CreateMap<RegistrationDTO, Registration>()
.ForMember(d => d.id, o => o.Ignore())
.ForMember(d => d.CreatedAt, o => o.UseValue(DateTime.Now))
.ForMember(d => d.Departments, o => o.MapFrom(s =>
{
var dbContext = new MyDbContext();
var departments = new List<int>(s.Departments)
.ConvertAll(input => dbContext.Departments.Find(input));
return departments;
}))
;
DbContext
デリゲート ブロック内の は、エンティティを ( )DbContext
に追加して呼び出すために使用するものと同じではないため、これは機能しません。異なるコンテキストに関連付けられたエンティティがある場合、データベース内でエンティティが重複することになります (または、主キーの重複による SQL 例外が発生する可能性があります)。Registration
dbContext.Registrations.Add(reg)
SaveChanges
Department
アップデート
私のエンティティと DTO の両方に 15 以上のフィールドがあるため、AutoMapper を選択しました。この 2 つの唯一の違いは、ID、作成日、最終更新日など、私のエンティティが持つデータベース固有のものです。使用しないというアドバイスを維持しますか?この場合の AutoMapper は、私のエンティティがここに投稿した単純化よりもはるかに大きいことを考慮して?
場合によります。15 以上の他のプロパティについて、それらはすべてスカラーですか? 外部キー プロパティ (コレクション以外のナビゲーション プロパティを管理するために公開されているもの) はありますか? カスタムリゾルバーを呼び出すものはいくつありますか?
DTO コレクション ナビゲーション プロパティ ( ) に automapper を使用することは絶対にありませんpublic virtual ICollection<SomeOtherEntity> OtherEntities { get; set; }
。また、外部キー ( ) を公開しない DTO 非コレクション ナビゲーション プロパティにオートマッパーを使用しようとはしませんpublic virtual SomeOtherEntity OtherEntity { get; set; }
。
ここでのコードの匂いは、DTO からエンティティへの呼び出しごとにCreateMap
、少なくとも 2 つの が存在することですIgnore
(作成日、最終更新日などは無視されます)。また、コレクション以外の nav プロパティが外部キー プロパティを公開する場合、fk プロパティを自動マップして機能しますが、実際の ( virtual
) nav プロパティを別の無視することになります。
また、ドメイン コードに関して言えば、それは記録のシステムであり、AutoMapper の背後に一部の詳細を隠すのではなく、それを読むときにすべてを公開するのに役立ちます。以下を考えてみてください -- これはより明確で、多少冗長ですが、すべてのドメイン転送コードが 1 つのソース ファイルに示されているため、必ずしも悪いことではないと思います。
var reg = new Registration
{
name = dto.name,
prop1 = dto.prop1,
prop2 = dto.prop2,
...
propN = dto.propN
};
CreateMap
ブートストラッパーで必要なすべての余分な行 (ignores、カスタム リゾルバーなど) と、ここにある余分な行の数を比較してください。最終的にはあなたの電話です。うまくいけば、これが役に立ちます。