2010-01-27 12 views
5

Je ne sais pas si le titre a du sens, mais voici ce que je fais. J'utilise AutoMapper pour mapper mes Entity Framework Entities à mes objets DTO et vice versa. Le problème survient lorsque j'essaie de mapper les données DTO à l'entité EF. Il n'y a pas de propriété pour mappage de propriété pour EntityKey. Pour résoudre ce problème, je fais un peu comme ce qui suit:Existe-t-il un moyen générique d'utiliser ValueResolver d'AutoMapper pour mapper des valeurs EntityKey pour les entités EF?

 Mapper.CreateMap<VideoDTO, Video>() 
      .ForMember(dest => dest.EntityKey, opt => 
opt.ResolveUsing<VideoEntityKeyResolver>()); 

La classe VideoEntityKeyResolver ressemble:

public class VideoEntityKeyResolver : ValueResolver<VideoDTO, EntityKey> 
{ 
    protected override EntityKey ResolveCore(VideoDTO source) 
    { 
     EntityKey key = new EntityKey("EntityFrameworkTestingEntities.Videos", 
      "VideoId", source.VideoId); 
     return key; 
    } 
} 

Je me demandais s'il y avait une façon plus générique de le faire où je pourrais avoir une classe avec un constructeur qui prend le nom de l'ensemble d'entités, le nom de la propriété clé et la valeur clé dans un constructeur. J'ai pensé à ajouter juste une propriété EntityKey à mes objets DTO qui ressemble beaucoup à traverser les flux car le point de créer les objets DTO était de graver le lien avec ma couche de données dans le reste de mon application .

Sur une note totalement indépendante (je peux créer une nouvelle question si nécessaire), où dois-je définir mes mappages lors de l'utilisation d'AutoMapper? Actuellement, je le fais dans le constructeur de mon objet contexte (qui est mon objet référentiel EF), mais je crois que c'est plutôt coûteux et tout simplement pas correct, cependant, cela fonctionne.

Répondre

8

Je ne suis pas allé jusqu'à tester, mais ce qui suit devrait fonctionner:

public class EntityKeyResolver<T, TProperty> : ValueResolver<T, EntityKey> where T : class 
{ 
    private Expression<Func<T, TProperty>> _propertyExpression; 
    private string _qualifiedEntitySetName; 
    private string _keyName; 

    public EntityKeyResolver(string qualifiedEntitySetName, string keyName, Expression<Func<T, TProperty>> propertyExpression) 
    { 
     _qualifiedEntitySetName = qualifiedEntitySetName; 
     _keyName = keyName; 
     _propertyExpression = propertyExpression; 
    } 

    protected override EntityKey ResolveCore(T source) 
    { 
     return new EntityKey(_qualifiedEntitySetName, _keyName, ExpressionHelper.GetValue(_propertyExpression)); 
    } 
} 

Le ExpressionHelper est une classe statique que j'utilise pour aider à évaluer les expressions dans une variété de cas. La méthode GetValue ressemble à ceci:

internal static TProperty GetValue<T, TProperty>(T obj, Expression<Func<T, TProperty>> expression) where T : class 
{ 
    if (obj == null) 
    { 
     return default(TProperty); 
    } 

    Func<T, TProperty> func = expression.Compile(); 

    return func(obj); 
} 

Vous pouvez ensuite modifier votre code comme suit (en supposant VideoId est un Guid):

Mapper.CreateMap<VideoDTO, Video>()   
      .ForMember(dest => dest.EntityKey, opt => opt.ResolveUsing(new EntityKeyResolver<VideoDTO, Guid>("EntityFrameworkTestingEntities.Videos", "VideoId", v => v.VideoId))); 

Probablement un peu plus prolixe que vous vouliez. Une alternative au résolveur générique serait d'utiliser MapFrom pour cartographier la clé d'entité (ils sont à peu près également bavard):

Mapper.CreateMap<VideoDTO, Video>()   
       .ForMember(dest => dest.EntityKey, opt => opt.MapFrom(src => new EntityKey("EntityFrameworkTestingEntities.Videos", "VideoId", src.VideoId))); 

Quant à votre autre question, j'ai pris l'habitude de créer une classe statique initialise mes cartes et définit un booléen pour savoir si les mappages ont été créés ou non car vous n'avez besoin de l'appeler qu'une seule fois par AppDomain. Ensuite, dans le constructeur de mon référentiel, je viens d'appeler MapInitializer.EnsureMaps();

+0

Merci pour la réponse détaillée. La plupart de cela est sur ma tête, mais c'est plus moi que vous. Je suis toujours en train de lutter avec l'utilisation de lambda et autres. Quoi qu'il en soit, savez-vous s'il existe une méthode automapper qui vous permet d'assigner explicitement une valeur calculée à une propriété? Si c'est le cas, je pourrais simplement créer un objet EntityKey avec les paramètres nécessaires et mapper cette valeur à la propriété EntityKey sur mon entité. J'avais examiné la méthode MapFrom AutoMapper, mais je n'ai pas eu le temps d'y plonger. – jason

+0

J'allais suggérer cela comme une méthode plus simple, mais j'ai décidé de répondre directement à votre question. Je vais ajouter cela à la réponse. (Aussi, n'oubliez pas de voter et/ou d'accepter la réponse si vous le trouvez pour répondre à vos besoins) – mkedobbs

+0

Merci d'aller au-dessus et au-delà sur cette question. Cela m'a vraiment aidé! Je suis allé de l'avant et je me suis contenté de mapper une propriété EntityKey, ce qui semble avoir fonctionné. – jason