Entity Framework + AutoMapper (от сущности к DTO и от DTO к сущности)

У меня проблемы с использованием EF с AutoMapper. знак равно

Например :

I've got 2 related entities ( Customers and Orders ) and they're DTO classes :


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

Я делаю что-то неправильно?

Заранее спасибо !


person shkipper    schedule 21.05.2009    source источник
comment
Как выглядят ваши клиенты и заказы? Трудно сказать, что происходит, не видя их структуры ....   -  person marc_s    schedule 21.05.2009
comment
я тоже не могу .... У меня проблемы при сопоставлении списков entitycollection ‹t› и dto.   -  person Victor Rodrigues    schedule 12.08.2009
comment
Как упоминал @ geva30, вы должны позвонить Mapper.AssertConfigurationIsValid() после создания ваших карт, чтобы определить любые проблемы, которые могут возникнуть во время выполнения.   -  person Tr1stan    schedule 16.09.2011
comment
вы также можете попробовать EntitiesToDTOs, генератор DTO Entity Framework, используемый в качестве надстройки для Visual Studio: entitytodtos.codeplex.com   -  person kzfabi    schedule 02.01.2012


Ответы (8)


Проблема, с которой я столкнулся, была связана с обновлениями ссылок на EntityCollection. AutoMapper создает новый экземпляр отношения при отображении из DTO в Entity, и это не нравится EF.

Что решило мою проблему, так это настройка AutoMapper на использование целевого значения для моих свойств EntityCollection. В твоем случае:

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

Таким образом, AM не будет создавать новый экземпляр EntityCollection, а будет использовать тот, который пришел с исходной сущностью Customer.

Я все еще ищу способ автоматизировать это, но пока это решает мою проблему.

person Pablo Montilla    schedule 28.05.2010

Попробуйте сопоставить существующий объект:

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

И оставьте Ignore () на месте.

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

person ishakkulekci    schedule 29.12.2011

Ваша проблема в том, что Automapper теряет EntityKey, связанный с записью. Поскольку EntityFramework по умолчанию не обрабатывает POCO (простой старый объект CLR)

У Джея Циммермана есть хороший пример того, как с этим справиться. gd / 4NIcj Также от Ярослава Ковальски (я полагаю, что он входит в команду EF) есть этот пример использования POCO в EF, который может хорошо переводиться для использования с Automapper (у меня еще не было возможности его попробовать): http://blogs.msdn.com/jkowalski/archive/2008/09/09/persistence-ignorance-poco-adapter-for-entity-framework-v1.aspx

person user203510    schedule 05.11.2009

Я не уверен, в чем ваша проблема, но - когда я хотел использовать LINQToEntities (переключился на NHibernate),
мне удалось успешно использовать automapper.

Взгляните на код:

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);
    }
}

Это довольно загадочно, всегда воссоздает сопоставления, но это сработало. Надеюсь, это как-то поможет. :)

person Arnis Lapsa    schedule 21.05.2009
comment
Не могли бы вы привести пример подключения AUtoMapper с использованием описанного вами кода? - person Oppositional; 04.06.2009
comment
@Oppositional общедоступный класс CustomerRepository ‹LinqGeneratedCustomer, Customer› {Customer lameMethod () {LinqGeneratedCustomer generatedCustomer; ... тралала ... return Map (createdCustomer};} - person Arnis Lapsa; 05.06.2009
comment
Не могли бы вы ответить на вопрос stackoverflow.com / questions / 9498962 /? - person LCJ; 29.02.2012

Теперь, с новой версией AutoMapper, рекомендуется использовать Queryable-Extensions:

При использовании ORM, такого как NHibernate или Entity Framework, со стандартными функциями AutoMapper Mapper.Map, вы можете заметить, что ORM будет запрашивать все поля всех объектов внутри графика, когда AutoMapper пытается сопоставить результаты к типу назначения.

Если ваша ORM предоставляет IQueryables, вы можете использовать вспомогательные методы AutoMapper QueryableExtensions для решения этой ключевой проблемы.

.ProjectTo () сообщит механизму сопоставления AutoMapper выдать предложение select в IQueryable, которое проинформирует платформу сущности о том, что ей нужно запрашивать только столбец Name таблицы Item, так же, как если бы вы вручную спроецировали свой IQueryable в OrderLineDTO с помощью Выберите пункт.

Создайте сопоставление:

Mapper.CreateMap<Customer, CustomerDto>();

И запрос проекта к dto:

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

AutoMapper очень выразителен, когда дело касается ошибок отображения. внимательно прочтите сообщение об исключении.

еще одна важная вещь - не забудьте вызвать Mapper.AssertConfigurationIsValid (); после создания сопоставлений. он выдает ошибку, если отображение неверно, тем самым предотвращая исключение позже во время выполнения приложения.

person geva30    schedule 18.10.2009

Вы должны игнорировать сопоставление некоторых свойств объекта, например:

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, вы должны увидеть свойства сущности, которые не могут быть сопоставлены, и проигнорировать их, как указано выше.

person codrin    schedule 07.10.2011

Как вы можете прочитать здесь, вы нужно сделать следующее

Вы можете обновлять объекты с помощью AutoMapper. Вот как: передать как DTO, так и объект сущности методу Map AutoMapper. Вот что делает этот код:

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

Также остерегайтесь проблем с отображением, подобных описанной здесь

Эти советы сработали для меня.

person Dmytro I.    schedule 18.01.2014