Подтвердить что ты не робот

Entity Framework + AutoMapper (Entity для DTO и DTO для объекта)

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

например:

У меня есть 2 связанных объекта (Клиенты и Заказы) и они являются классами 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

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

Спасибо в Advance!

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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

Ответ 3

Я не уверен, в чем проблема, но - когда я хотел использовать 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);
    }
}

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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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

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

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

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

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

Mapper.CreateMap<Customer, CustomerDto>();

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

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

Ответ 8

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

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

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

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

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