Entity Framework + AutoMapper (сущность для DTO и DTO для сущности) - PullRequest
20 голосов
/ 21 мая 2009

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

например:

У меня есть 2 связанных объекта (клиенты и заказы) и они классы DTO:


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

<p>class OrderDTO
{
   public string OrderID {get;set;}
   public string OrderDetails {get;set;}
   public CustomerDTO Customers {get;set;}
}</p>

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

<p>//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

Я что-то не так делаю?

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

Ответы [ 8 ]

18 голосов
/ 28 мая 2010

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

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

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

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

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

5 голосов
/ 05 ноября 2009

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

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

4 голосов
/ 29 декабря 2011

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

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

И держите Игнорирование () на месте.

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

4 голосов
/ 21 мая 2009

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

Посмотрите на код:

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

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

3 голосов
/ 03 февраля 2016

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

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

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

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

Создать отображение:

Mapper.CreateMap<Customer, CustomerDto>();

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

var customerDto = 
   session.Query<Customer>().Where(customer => customer.Id == id)
   .Project().To<CustomerDto>()
   .Single();
2 голосов
/ 07 октября 2011

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

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 голосов
/ 18 октября 2009

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

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

0 голосов
/ 19 января 2014

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

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

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

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

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

...