2012-09-04 16 views
6

Come configurare il mapping AutoMapper quando si desidera utilizzare il comportamento dal metodo UseDestinationValue, ma solo quando la proprietà di destinazione NON è null.UseDestinationValue solo quando la proprietà di destinazione non è null

Qualcosa del genere:

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

EDIT

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; } 
} 

Ora esempio di utilizzo. Ho una classe ItemViewModel e desidero associarla alla classe Item.

configurazione Mapping:

Mapper.CreateMap<Item, ItemViewModel>() 
     .ForMember(x => x.Details, _ => _.UseDestinationValue()) 
  1. Primo caso - proprietà di destinazione Item.Details proprietà non è NULL. Ora voglio AutoMapper per utilizzare questa istanza di destinazione della proprietà Details, perché non è nulla.

    E la logica assomiglia a questo:

    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, a causa della presenza di UseDestinationValue, lascerà l'istanza item.Details e impostare solo item.Details.Info proprietà.

  2. Secondo caso - proprietà di destinazione Item.Details proprietà è NULL. Ora voglio AutoMapper per non utilizzare questa istanza nulla, ma crearne una nuova. La domanda è come configurare la mappatura per tenere conto di questo caso?

    La logica assomiglia a questo:

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

    PROBLEMA

    Qui ho un problema, perché dopo la mappatura, la proprietà item.Details sarà nulla (a causa di utilizzo di UseDestinationValue che è null in questo caso).

MOTIVO

NHibernate, dopo aver ottenuto l'entità dal database, lo mette in un proxy. Quindi la proprietà Details di un oggetto caricato non è di un tipo: ItemDetails, ma ItemDetailsNHibernateProxy - quindi devo usare questo tipo, quando voglio salvare questo oggetto esistente nel database in un secondo momento. Ma se questa proprietà è null, allora non posso usare un valore di destinazione nullo, quindi Automapper dovrebbe creare una nuova istanza.

Grazie, Chris

+0

Quindi vuoi fare qualcosa di diverso UseDestinationValue se è nullo? – PatrickSteele

+0

Sì, voglio fare qualcos'altro quando la proprietà di destinazione È NULL. – cryss

+0

Puoi fornire qualche esempio di codice funzionante che ti mostri come vuoi che le cose vengano mappate rispetto a ciò che Auotmapper fa attualmente. Non sto ottenendo quello che stai chiedendo. – PatrickSteele

risposta

0

credo che l'opzione NullSubstitute avrebbe funzionato per voi.Vedere: http://weblogs.asp.net/psteele/archive/2011/03/18/automapper-handling-null-members.aspx

EDIT

Sembra che potrebbe essere necessario aggiungere un po 'di logica condizionale per la mappatura per i dettagli (e saltare l'opzione UseDestinationValue):

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

NullSubstitute è utile quando il valore di origine è nullo. – cryss

0

Ho avuto questo stesso problema trattando con le entità di NHibernate e ho trovato una soluzione piuttosto semplice.

È necessario inizializzare la proprietà Details nel costruttore ItemViewModel. In questo modo il valore di destinazione non è mai nullo. Ovviamente questo non funziona in casi più complessi (come le classi astratte).

1

Aveva lo stesso problema, ma con EF. Il commento di Cryss sull'uso di BeforeMap mi ha indirizzato nella giusta direzione.

ho finito con un codice simile a:

Nella Configurazione() Metodo:

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

allora l'azione:

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