2012-08-05 6 views
5

Estoy empezando a implementar AutoMapper, primero logré integrarlo con Castle.Windsor, que ya estoy usando. Ahora tengo una entidad Post que quiero asignar a LinkPostModel o ImagePostModel. Ambos heredan de PostModelAutoMapper ¿Asignar un mapa a un tipo diferente basado en una enumeración?

1) Esto es lo que tengo hasta ahora:

public class PostModelFromPostEntityConverter : ITypeConverter<Post, PostModel> 
{ 
    private readonly IPostService postService; 

    public PostModelFromPostEntityConverter(IPostService postService) 
    { 
     if (postService == null) 
     { 
      throw new ArgumentNullException("postService"); 
     } 
     this.postService = postService; 
    } 

    public PostModel Convert(ResolutionContext context) 
    { 
     Post post = (Post)context.SourceValue; 
     Link link = post.Link; 
     if (link.Type == LinkType.Html) 
     { 
      return new LinkPostModel 
      { 
       Description = link.Description, 
       PictureUrl = link.Picture, 
       PostId = post.Id, 
       PostSlug = postService.GetTitleSlug(post), 
       Timestamp = post.Created, 
       Title = link.Title, 
       UserMessage = post.UserMessage, 
       UserDisplayName = post.User.DisplayName 
      }; 
     } 
     else if (link.Type == LinkType.Image) 
     { 
      return new ImagePostModel 
      { 
       PictureUrl = link.Picture, 
       PostId = post.Id, 
       PostSlug = postService.GetTitleSlug(post), 
       Timestamp = post.Created, 
       UserMessage = post.UserMessage, 
       UserDisplayName = post.User.DisplayName 
      }; 
     } 
     return null; 
    } 
} 

Obviamente el punto en la implementación de AutoMapper es la eliminación de código de repetición de este tipo, así que ¿cómo se supone que voy a trazar la materia común , antes de añadir mis reglas personalizadas (como si la cláusula-)

lo ideal sería que esto sea algo como:

public class PostModelFromPostEntityConverter : ITypeConverter<Post, PostModel> 
{ 
    [...] 

    public PostModel Convert(ResolutionContext context) 
    { 
     Post post = (Post)context.SourceValue; 
     Link link = post.Link; 
     if (link.Type == LinkType.Html) 
     { 
      return Mapper.Map<Post, LinkPostModel>(post); 
      // and a few ForMember calls? 
     } 
     else if (link.Type == LinkType.Image) 
     { 
      return Mapper.Map<Post, ImagePostModel>(post); 
      // and a few ForMember calls? 
     } 
     return null; 
    } 
} 

2) Una vez completada esta asignación. Tengo un mapeo "padre", donde tengo que asignar un IEnumerable<Post> el siguiente modelo:

public class PostListModel : IHasOpenGraphMetadata 
{ 
    public OpenGraphModel OpenGraph { get; set; } // og:model just describes the latest post 
    public IList<PostModel> Posts { get; set; } 
} 

Así que, básicamente, que iba a necesitar otra TypeConverter(¿verdad?), lo que me permite MAPA la lista de puestos de primeros , y luego crear el og:model

tengo esto, pero se siente especie de torpe, creo que podría ser mejor:

public class PostListModelFromPostEntityEnumerableConverter : ITypeConverter<IEnumerable<Post>, PostListModel> 
{ 
    public PostListModel Convert(ResolutionContext context) 
    { 
     IEnumerable<Post> posts = (IEnumerable<Post>)context.SourceValue; 
     PostListModel result = new PostListModel 
     { 
      Posts = posts.Select(Mapper.Map<Post, PostModel>).ToList() 
     }; 
     Post first = posts.FirstOrDefault(); 
     result.OpenGraph = Mapper.Map<Post, OpenGraphModel>(first); 
     return result; 
    } 
} 

3) No ejecuté el código todavía, así que me viene a la mente otra pregunta, ¿y por eso las asignaciones no están fuertemente tipadas en los conversores?

IEnumerable<Post> posts = (IEnumerable<Post>)context.SourceValue; 

donde realmente podría ser

IEnumerable<Post> posts = context.SourceValue; 

Respuesta

1

Tratando de conseguir Nigromante placa.
Hoy en día, esta tarea se puede resolver mucho más fácilmente con el uso de ConstructUsing. Los campos específicos de la función deben rellenarse en la acción proporcionada, pero todos los campos comunes irán a ForMember ejecución del mapeo. Las colecciones en este caso no requieren configuraciones de lógica/mapeo adicionales. Clases que también tienen una propiedad de tipo colección.

cfg.CreateMap<Post, PostModel>() 
    .ConstructUsing(p => 
    { 
     switch (p.Type) 
     { 
      case LinkType.Html: return new LinkPostModel 
      { 
       Title = p.Description 
       // other specific fields 
      }; 
      case LinkType.Image: return new ImagePostModel 
      { 
       // other specific fields 
      }; 
     } 
     return null; 
    }) 
    .ForMember(x => x.PostId, m => m.MapFrom(p => p.Id)); 
cfg.CreateMap<PostList, PostListModel>(); 
Cuestiones relacionadas