practices mvc framework best c# entity-framework automapper dto

c# - mvc - Entity Framework+AutoMapper(Entidad a DTO y DTO a entidad)



dto c# mvc (8)

Tengo algunos problemas al utilizar EF con AutoMapper. = /

por ejemplo :

Tengo 2 entidades relacionadas (Clientes y Pedidos) y son clases 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

¿Estoy haciendo algo mal?

Gracias por adelantado !


Ahora, con la nueva versión de AutoMapper, la forma recomendada es utilizar Queryable-Extensions :

Cuando use un ORM como NHibernate o Entity Framework con las funciones estándar Mapper.Map de AutoMapper, puede observar que el ORM consultará todos los campos de todos los objetos dentro de un gráfico cuando AutoMapper esté intentando asignar los resultados a un tipo de destino.

Si su ORM expone IQueryables, puede usar los métodos de ayuda QueryableExtensions de AutoMapper para abordar este problema clave.

El .ProjectTo () le dirá al motor de mapeo de AutoMapper que emita una cláusula de selección al IQueryable que informará al marco de la entidad que solo necesita consultar la columna Nombre de la tabla del Artículo, igual que si proyectara manualmente su IQueryable a un OrderLineDTO con un Seleccione la cláusula.

Crear un mapeo:

Mapper.CreateMap<Customer, CustomerDto>();

Y proyecto de consulta a dto:

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


AutoMapper es muy expresivo cuando se trata de un error de mapeo. lea el mensaje de excepción cuidadosamente.

otra cosa importante es recordar llamar a Mapper.AssertConfigurationIsValid (); después de crear las asignaciones. genera un error si la asignación es incorrecta, lo que evita una excepción más adelante en el tiempo de ejecución de la aplicación.


Como puedes leer here necesitas hacer lo siguiente

Puede actualizar las entidades con AutoMapper. A continuación le indicamos cómo: pase el DTO y el objeto de entidad al método Map de AutoMapper. Eso es lo que hace este código:

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

También tenga cuidado con los problemas de mapeo como el que se describe here

Estos consejos funcionaron para mí.


Debería ignorar el mapeo de algunas propiedades de la entidad como tal:

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

Si examina el mensaje de la excepción lanzada por Automapper, debería ver las propiedades de la entidad que no se pueden asignar e ignorarlas como se indicó anteriormente.


El problema que tuve estaba relacionado con las actualizaciones de las referencias de EntityCollection. AutoMapper crea una nueva instancia de la relación cuando se mapea del DTO a la Entidad, y eso no complace al EF.

Lo que resolvió mi problema fue configurar AutoMapper para usar el valor de destino para mis propiedades de EntityCollection. En tu caso:

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

De esa manera, AM no creará una nueva instancia de EntityCollection, y utilizará la que vino con la entidad del Cliente original.

Todavía estoy trabajando para una forma de automatizar esto, pero por ahora resuelve mi problema.



No estoy seguro de cuál es su problema, pero cuando quise usar LINQToEntities (cambiado a NHibernate),
Me las arreglé para usar automapper con éxito.

Echa un vistazo al código:

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

Es bastante críptico, siempre recrea las asignaciones, pero funcionó. Espero que ayude de alguna manera. :)


Su problema es porque Automapper pierde la EntityKey asociada con el registro. Como el EntityFramework no maneja de forma predeterminada los POCO (objeto CLR antiguo simple)

Jay Zimmerman tiene un buen ejemplo aquí de cómo manejar esto desde. gd / 4NIcj También de Jaroslaw Kowalski (parte del equipo de EF, creo) tiene este ejemplo para usar POCO''s dentro de EF, que puede traducirse bien para usar con Automapper (aún no he tenido la oportunidad de probarlo): http://blogs.msdn.com/jkowalski/archive/2008/09/09/persistence-ignorance-poco-adapter-for-entity-framework-v1.aspx