2012-09-04 20 views
6

Cómo configurar la asignación de AutoMapper cuando quiero usar el comportamiento desde el método UseDestinationValue, pero solo cuando la propiedad de destino NO es null.UseDestinationValue solo cuando la propiedad de destino no es nula

Algo así:

Mapper.CreateMap<Item, ItemViewModel>() 
    .ForMember(x => x.Details, _ => _.UseDestinationValue(dontUseWhenNullDestination: true)) 

EDITAR

class ItemDetails { 
    public string Info { get; set; } 
    public string ImportantData { get; set; } // only in Domain, not in ViewModel 
} 

class Item { 
    public ItemDetails Details { get; set; } 
} 

class ItemDetailsViewModel { 
    public string Info { get; set; } 
} 

class ItemViewModel { 
    public ItemDetailsViewModel Details { get; set; } 
} 

Ahora ejemplo de uso. Tengo una clase ItemViewModel y quiero asignarla a la clase Item.

configuración de asignación:

Mapper.CreateMap<Item, ItemViewModel>() 
     .ForMember(x => x.Details, _ => _.UseDestinationValue()) 
  1. Primer caso - propiedad de destino Item.Details propiedad no es nulo. Ahora quiero que AutoMapper use esta instancia de destino de la propiedad Details, porque no es nulo.

    Y la lógica es similar a esto:

    var item = new Item { 
        Details = new Details { 
         Info = "Old text", 
         ImportantData = "Data" 
        } 
    }; 
    
    var itemViewModel = new ItemViewModel { 
        Details = new DetailsViewModel { 
         Info = "New text" 
        } 
    };  
    
    Mapper.Map(itemViewModel, item); 
    

    AutoMapper, debido a la presencia de UseDestinationValue, dejará la instancia item.Details y establecer solamente item.Details.Info propiedad.

  2. Segundo caso - propiedad de destino Item.Details propiedad es NULL. Ahora quiero que AutoMapper no use esta instancia nula, pero cree una nueva. La pregunta es cómo configurar el mapeo para tener en cuenta este caso.

    La lógica es similar a esto:

    var item = new Item { 
        Details = null 
    }; 
    
    var itemViewModel = new ItemViewModel { 
        Details = new DetailsViewModel { 
         Info = "New text" 
        } 
    }; 
    
    Mapper.Map(itemViewModel, item); 
    

    PROBLEMA

    Aquí tengo un problema, porque después de la cartografía, la propiedad item.Details será nulo (debido al uso de UseDestinationValue que es null en este caso).

RAZÓN

NHibernate, después de conseguir la entidad de la base de datos, lo pone en un proxy. Entonces, la propiedad Details de un objeto cargado no es de un tipo: ItemDetails, sino ItemDetailsNHibernateProxy, así que tengo que usar este tipo, cuando deseo guardar este objeto existente en la base de datos más adelante. Pero si esta propiedad es null, entonces no puedo usar un valor de destino nulo, por lo que Automapper debe crear una nueva instancia.

Gracias, Chris

+0

Entonces, ¿quieres hacer algo que no sea UseDestinationValue si es nulo? – PatrickSteele

+0

Sí, deseo hacer algo más cuando la propiedad de destino ES NULA. – cryss

+0

¿Podría proporcionar algún código de muestra de trabajo que le muestre cómo desea que las cosas se asignen frente a lo que Auotmapper hace actualmente? No entiendo lo que estás preguntando. – PatrickSteele

Respuesta

0

creo que la opción NullSubstitute funcionaría para usted.Ver: http://weblogs.asp.net/psteele/archive/2011/03/18/automapper-handling-null-members.aspx

EDITAR

Parece que puede que tenga que añadir un poco de lógica condicional para el mapeo de detalles (y omitir la opción UseDestinationValue):

.ForMember(d => d.Details, 
    o => o.MapFrom(s => s.Details == null ? new ItemDetails() : Mapper.Map<ItemDetailsViewModel, ItemDetails>(s.Details)) 
+1

NullSubstitute es útil cuando el valor de origen es nulo. – cryss

0

que tenía este mismo problema tratar con las entidades de NHibernate y encontré una solución bastante simple para ello.

Debe inicializar la propiedad Details en el constructor ItemViewModel. De esta forma, el valor de destino no es nulo nunca. Por supuesto, esto no funciona en casos más complejos (como clases abstractas).

1

Tenía este mismo problema, pero con EF. El comentario de Cryss sobre el uso de BeforeMap me indicó la dirección correcta.

que terminó con un código similar a: Método

En el Configurar():

Mapper.CreateMap<ItemViewModel, Item>() 
      .AfterMap((s, d) => { MapDetailsAction(s, d); }) 
      .ForMember(dest => dest.Details, opt => opt.UseDestinationValue()); 

entonces la acción:

Action<ItemViewModel, Item> MapDetailsAction = (source, destination) => 
     { 
      if (destination.Details == null) 
      { 
       destination.Details = new Details(); 
       destination.Details = 
        Mapper.Map<ItemViewModel, Item>(
        source.Details, destination.Details); 
      } 
     }; 
Cuestiones relacionadas