collections - formember - automapper nested mapping
Mapeo de colección secundaria de solo lectura con AutoMapper (2)
Creo que si va a proteger las propiedades por razones de buena lógica de negocios, sería malo si AutoMapper las eludía al hacer su asignación. En situaciones como esta, prefiero abandonar la sintaxis fluida y colocar la lógica de creación en su propio método como este:
private Parent MapParentDTOToParent(ParentDTO source)
{
var parent = new Parent();
// Business logic here
return parent
}
y entonces:
Mapper.CreateMap<ParentDTO, Parent>().ConvertUsing(MapParentDTOToParent);
Encuentro esto más fácil de seguir que tener muchas declaraciones de ignorar.
No es tanto una pregunta, ya que he encontrado una manera de hacer lo que quiero, pero parece que debería haber una mejor manera de hacerlo. He buscado por todas partes y no he encontrado nada.
Básicamente, tengo lo que considero un modelo de objeto muy estándar.
public class Parent
{
private readonly IList<Child> _children = new List<Child>();
public IEnumerable<Child> Children { get { return _children; } }
public void AddChild(Child child)
{
child.Parent = this;
_children.Add(child);
}
}
y
public class Child
{
public Parent Parent { get; set; }
}
(He omitido propiedades irrelevantes para el problema y la comprobación y protección de errores en aras de la claridad ...)
public class ParentDTO
{
List<ChildDTO> Children = new List<ChildDTO>();
}
y
public class ChildDTO
{
}
La razón por la que estoy usando un método para agregar hijos a la colección es para mantener el control de la lógica empresarial que debe procesarse cuando se agrega un hijo.
Con el mapeo estándar de:
Mapper.CreateMap<Parent, ParentDTO>();
Mapper.CreateMap<ParentDTO, Parent>();
Mapper.CreateMap<Child, ChildDTO>();
Mapper.CreateMap<ChildDTO, Child>();
Parece que funciona bien desde la capa de servicio. Los hijos del objeto de dominio se asignan perfectamente a la lista de instancias de ChildDTO
.
Sin embargo, cuando se mapea de la otra manera, la colección en el modelo de dominio no está establecida, porque es de solo lectura, obviamente. No parece haber ninguna forma de establecer directamente el campo privado utilizando AutoMapper. He intentado varias sugerencias encontradas aquí, y otras partes de internet.
Al final, se me ocurrió la siguiente asignación:
Mapper.CreateMap<ParentDTO, Parent>()
.ForMember(m => m.Children, o => o.Ignore())
.AfterMap((s, d) =>
{
foreach(var c in s.Children)
d.AddChild(Mapper.Map<ChildDTO, Child>(c));
});
Esto funciona como yo lo requiera. Sin embargo, no puedo evitar sentir que tiene que haber una mejor manera, y no he probado esto con un padre existente al que se le ha modificado a los niños y tal vez se han agregado y eliminado, así que sé que todavía no es correcto. En última instancia, este modelo de dominio se mantiene utilizando NHibernate, así que tengo que preocuparme por eso. Pero, una cosa a la vez. :)
Esperemos que esto pueda ayudar a otra persona que se encuentre con el mismo problema, y tal vez alguien que lo resuelva adecuadamente pueda corregirme.
No me gusta tener lógica dentro de la propiedad getter o setter, pero ¿qué hay de agregar setter a la propiedad Children de la clase Parent?
public class Parent
{
private readonly IList<Child> _children = new List<Child>();
public IEnumerable<Child> Children
{
get => _children;
set => AddChildren(value);
}
public void AddChild(Child child)
{
child.Parent = this;
_children.Add(child);
}
private void AddChildren(IEnumerable<Child> children)
{
_children.Clear();
foreach (var child in children)
{
AddChild(child);
}
}
}
Y la lógica AfterMap no es más necesaria. La configuración del mapeo será simple.
Mapper.CreateMap<ParentDTO, Parent>();