Entity Framework + AutoMapper (Entity to DTO et DTO to Entity)
j'ai quelques problèmes avec L'utilisation de EF avec AutoMapper. = /
par exemple :
j'ai 2 entités liées ( clients et commandes ) et ce sont des cours de 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
je fais quelque chose de mal?
Merci d'Avance !
8 réponses
le problème que j'avais était lié à des mises à jour des références EntityCollection. AutoMapper crée une nouvelle instance de la relation lors de la correspondance de la DTO à L'entité, et cela ne plaît pas à L'EF.
ce qui a résolu mon problème a été la configuration D'AutoMapper pour utiliser la valeur de destination pour mes propriétés EntityCollection. Dans ton cas:
Mapper.CreateMap< CustomerDTO , Customers >().ForMember(c => c.Orders, o => o.UseDestinationValue());
de cette façon AM ne créera pas une nouvelle instance EntityCollection, et utilisera ce qui est venu avec le client original entité.
je travaille toujours à trouver un moyen d'automatiser ça, mais pour l'instant ça résout mon problème.
votre problème est que Automapper perd L'EntityKey associé à l'enregistrement. Comme L'Entitefram Framework ne gère pas par défaut POCO's (Plain Old CLR Object)
Jay Zimmerman a un bon exemple ici de la façon de gérer cela à partir des SI. gd / 4NIcj Aussi de Jaroslaw Kowalski (partie de L'équipe EF je crois ) a cet exemple pour l'utilisation de POCO au sein de EF, qui peut traduire bien à utiliser avec Automapper (Je n'ai pas encore eu la chance de l'essayer) : http://blogs.msdn.com/jkowalski/archive/2008/09/09/persistence-ignorance-poco-adapter-for-entity-framework-v1.aspx
Je ne suis pas sûr de ce qu'est votre problème, mais-quand je voulais utiliser LINQToEntities (commuté en NHibernate),
j'ai réussi à utiliser automapper avec succès.
regardez le code:
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);
}
}
c'est assez cryptique, il recrée toujours des mappages, mais ça a marché. J'espère qu'elle vous aide en quelque sorte. :)
Essayez d'associer à un objet existant:
entity = Mapper.Map<MyDTO, NyEntity>(dto, entity);
Et de garder l'Ignore()'s en place.
http://groups.google.com/group/automapper-users/browse_thread/thread/24a90f22323a27bc?fwc=1&pli=1
maintenant, avec la nouvelle version D'AutoMapper, la façon recommandée est d'utiliser Queryable-Extensions:
Lorsqu'on utilise un ORM tel que NHibernate ou Entity Framework avec AutoMapper standard du Mappeur.Fonctions de la carte, vous pouvez noter que le ORM va requête tous les champs de tous les objets dans un graphique quand AutoMapper tente de faire correspondre les résultats à un type de destination.
si votre ORM expose des Iquerables, vous pouvez utiliser AutoMapper de l' Les méthodes d'aide de QueryableExtensions pour répondre à cette douleur clé.
le .ProjectTo () avertira le moteur de cartographie D'AutoMapper pour émettre une clause select à L'IQueryable qui informera l'entité cadre qu'il ne doit interroger la colonne Nom de l'Élément table, comme si vous aviez projeté manuellement votre IQueryable OrderLineDTO avec une clause Select.
Créer un mapping:
Mapper.CreateMap<Customer, CustomerDto>();
et requête de projet à dto:
var customerDto =
session.Query<Customer>().Where(customer => customer.Id == id)
.Project().To<CustomerDto>()
.Single();
AutoMapper est très expressif en ce qui concerne les erreurs de mappage. lisez attentivement le message d'exception.
une autre chose importante est de ne pas oublier d'appeler Mapper.AssertConfigurationIsValid (); après avoir créé les mappings. il donne une erreur si la cartographie est faux, empêchant ainsi une exception plus tard dans l'exécution de l'application.
Vous devriez ignorer la cartographie de certaines propriétés d'entity comme so:
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 vous examinez le message de l'exception lancée par Automapper, vous devriez voir les propriétés de l'entité qui ne peuvent pas être mappées et les ignorer comme ci-dessus.
Comme vous pouvez le lire ici vous devez faire ce qui suit
Vous pouvez mettre à jour des entities avec AutoMapper. Voici comment: passez la DTO et l'objet entity à la méthode Map D'AutoMapper. C'est ce que ce code:
custExisting = Mapper.Map(Of CustomerDTO, Customer)(custDTO, custExisting)
attention aussi aux problèmes de mappage comme celui décrit ici
ces conseils ont fonctionné pour moi.