web-dev-qa-db-ja.com

Entity Framework + AutoMapper(エンティティからDTOおよびDTOからエンティティ)

AutoMapperでEFを使用すると問題が発生します。 = /

例えば ​​:

2つの関連エンティティ(CustomersとOrders)があり、それらはDTOクラスです:


class CustomerDTO
{
   public string CustomerID {get;set;}
   public string CustomerName {get;set;}
   public IList< OrderDTO > Orders {get;set;}
}


class OrderDTO { public string OrderID {get;set;} public string OrderDetails {get;set;} public CustomerDTO Customers {get;set;} }


//when mapping Entity to DTO the code works Customers cust = getCustomer(id); Mapper.CreateMap< Customers, CustomerDTO >(); Mapper.CreateMap< Orders, OrderDTO >(); CustomerDTO custDTO = Mapper.Map(cust);


//but when i try to map back from DTO to Entity it fails with AutoMapperMappingException. Mapper.Reset(); Mapper.CreateMap< CustomerDTO , Customers >(); Mapper.CreateMap< OrderDTO , Orders >(); Customers customerModel = Mapper.Map< CustomerDTO ,Customers >(custDTO); // exception is thrown here

私は何か間違ったことをしていますか?

前もって感謝します !

20
shkipper

私が抱えていた問題は、EntityCollection参照の更新に関連していました。 AutoMapperは、DTOからエンティティにマッピングするときにリレーションの新しいインスタンスを作成しますが、これはEFを満足させません。

私の問題を解決したのは、EntityCollectionプロパティの宛先値を使用するようにAutoMapperを構成することでした。あなたの場合:

Mapper.CreateMap< CustomerDTO , Customers >().ForMember(c => c.Orders, o => o.UseDestinationValue());

そうすれば、AMは新しいEntityCollectionインスタンスを作成せず、元のCustomerエンティティに付属しているインスタンスを使用します。

私はまだこれを自動化する方法に取り組んでいますが、今のところそれは私の問題を解決します。

18
Pablo Montilla

問題は、Automapperがレコードに関連付けられたEntityKeyを失うためです。 EntityFrameworkはデフォルトではPOCO(Plain Old CLR Object)を処理しないため

Jay Zimmermanは、これを処理する方法の良い例をここに示しています。 Gd/4NIcjまた、Jaroslaw Kowalski(私が信じているEFチームの一部)から、EF内でPOCOを使用するためのこの例があります。これは、Automapperで使用するのに適しています(まだ試す機会がありません): http://blogs.msdn.com/jkowalski/archive/2008/09/09/persistence-ignorance-poco-adapter-for-entity-framework-v1.aspx

5
user203510

既存のオブジェクトにマッピングしてみてください。

entity = Mapper.Map<MyDTO, NyEntity>(dto, entity); 

そして、Ignore()を所定の位置に保持します。

http://groups.google.com/group/automapper-users/browse_thread/thread/24a90f22323a27bc?fwc=1&pli=1

4
ishakkulekci

あなたの問題が何であるかはわかりませんが、LINQToEntities(NHibernateに切り替え)を使用したいときは、
オートマッパーの使用に成功しました。

コードを見てください:

public class SimpleMapper<TFrom, TTo>
{
    public static TTo Map(TFrom fromModel)
    {
        Mapper.CreateMap<TFrom, TTo>();
        return Mapper.Map<TFrom, TTo>(fromModel);
    }

    public static IList<TTo> MapList(IList<TFrom> fromModel)
    {
        Mapper.CreateMap<TFrom, TTo>();
        return Mapper.Map<IList<TFrom>, IList<TTo>>(fromModel);
    }
}

public class RepositoryBase<TModel, TLINQModel>
{
    public IList<TModel> Map<TCustom>(IList<TCustom> model)
    {
        return SimpleMapper<TCustom, TModel>.MapList(model);
    }

    public TModel Map(TLINQModel model)
    {
        return SimpleMapper<TLINQModel, TModel>.Map(model);
    }

    public TLINQModel Map(TModel model)
    {
        return SimpleMapper<TModel, TLINQModel>.Map(model);
    }

    public IList<TModel> Map(IList<TLINQModel> model)
    {
        return SimpleMapper<TLINQModel, TModel>.MapList(model);
    }

    public IList<TLINQModel> Map(IList<TModel> model)
    {
        return SimpleMapper<TModel, TLINQModel>.MapList(model);
    }
}

それはかなり不可解で、常にマッピングを再作成しますが、機能しました。なんとなくお役に立てば幸いです。 :)

4
Arnis Lapsa

現在、AutoMapperの新しいバージョンでは、推奨される方法は Queryable-Extensions を使用することです。

AutoMapperの標準Mapper.Map関数でNHibernateやEntityFrameworkなどのORMを使用する場合、AutoMapperがマップしようとすると、ORMがグラフ内でクエリを実行することに気付く場合がありますすべてのオブジェクトのすべてのフィールド結果は宛先タイプになります。

ORMがIQueryablesを公開している場合は、AutoMapperのQueryableExtensionsヘルパーメソッドを使用して、この重要な問題に対処できます。

.ProjectTo()は、AutoMapperのマッピングエンジンにIQueryableにselect句を発行するように指示します。これにより、IQueryableをOrderLineDTOに手動で投影した場合と同様に、ItemテーブルのName列のみをクエリする必要があることをエンティティフレームワークに通知します。句を選択します。

マッピングを作成します。

Mapper.CreateMap<Customer, CustomerDto>();

そして、dtoへのプロジェクトクエリ:

var customerDto = 
   session.Query<Customer>().Where(customer => customer.Id == id)
   .Project().To<CustomerDto>()
   .Single();
3
Dvor_nik

AutoMapperは、マッピングエラーに関して非常に表現力豊かです。例外メッセージを注意深く読んでください。

もう1つの重要なことは、Mapper.AssertConfigurationIsValid();を呼び出すことを忘れないことです。マッピングを作成した後。マッピングが間違っているとエラーが発生するため、アプリケーションランタイムの後半で例外が発生しなくなります。

2
geva30

次のような一部のエンティティプロパティのマッピングは無視する必要があります。

Mapper.CreateMap<CustomerDto, Customer>()
                .ForMember(dest => dest.EntityKey, opt => opt.Ignore())
                .ForMember(dest => dest.Licenses, opt => opt.Ignore())
                .ForMember(dest => dest.AccessCodes, opt => opt.Ignore());

Automapperによってスローされた例外からのメッセージを調べると、マップできないエンティティプロパティが表示され、上記のように無視されます。

2
codrin

あなたが読むことができるように ここ あなたは以下をする必要があります

AutoMapperを使用してエンティティを更新できます。方法は次のとおりです。DTOとエンティティオブジェクトの両方をAutoMapperのMapメソッドに渡します。これがこのコードの機能です。

custExisting = Mapper.Map(Of CustomerDTO,  Customer)(custDTO, custExisting)

また、説明されているようなマッピングの問題にも注意してください ここ

これらのヒントは私のために働いた。

0
Dmytro I.