2011-01-24 10 views
6

Sto utilizzando ValueInjecter per mappare le proprietà da un modello di dominio a un DTO servito tramite un livello di servizio. Il servizio in questione accetta anche gli aggiornamenti ... quindi viene passato un DTO aggiornato che viene quindi iniettato nell'oggetto dominio e salvato.Valore Injecter: Dto to Domain Model (NHibernate)

// Domain 
    public class Member 
    { 
     public Country Country { get; set; } 
    } 

    public class Country 
    { 
     public string Code { get; set; } 
     public string Name { get; set; } 
    } 

    //Dto 
    public class MemberDto 
    { 
     public string CountryCode { get; set; } 
    } 

    //Transformation Method attempt 1 
    public Member InjectFromDto (MemberDto dto, Member source) 
    { 
     source = source.InjectFrom<UnflatLoopValueInjection>(dto); 
     return source; 
    } 

Ora tutto questo codice di cui sopra non fa altro che aggiorna il Member.Country.Code proprietà che ovviamente non è quello che ho bisogno di fare.

Così dalla documentazione, ho pensato che avevo bisogno di creare un override e ottenuto questo:

public class CountryLookup: UnflatLoopValueInjection<string, Country> 
    { 
     protected override Country SetValue(string sourcePropertyValue) 
     { 
      return countryService.LookupCode(sourcePropertyValue); 
     } 
    } 


//revised transformation call 
//Transformation Method attempt 2 
    public Member InjectFromDto (MemberDto dto, Member source) 
    { 
     source = source.InjectFrom<UnflatLoopValueInjection>(dto) 
         .InjectFrom<CountryLookup>(dto); 
     return source; 
    } 

Il mio problema è durante il debug, CountryLookup non viene mai chiamato.

Possibili motivi che mi vengono in mente:

  • classi NHibernate proxy causando valore injecter di non corrispondere al tipo di paese? Questo non ha senso perché funziona durante l'appiattimento.
  • Forse lo spiattellamento non spara per qualche motivo. Cioè Dto è CountryCode e dominio è Country.Code

ho bisogno di utilizzare la proprietà CountryCode sul Dto per chiamare un countryService.LookupCode per restituire l'oggetto corretto da utilizzare durante l'iniezione di aggiornamento.

+0

dicci cosa stai cercando di ottenere, il primo tentativo funziona, ma non è quello che ti serve, di cosa hai bisogno? – Omu

+0

l'iniezione denominata CountryLookup verrà sparpagliata da stringa a Paese, il che significa che ottiene il valore da CountryCode di tipo stringa e lo inserisce in Country.Code del tipo Paese – Omu

+0

@Omu che è corretto, ad esempio se l'oggetto Paese è Paese: {Codice : USA, Name: United States} e my Dto passa in CountryCode: "CA" imposta semplicemente la proprietà Country.Code su CA e lascia la proprietà 'Name' come Stati Uniti. Ricorda che sto aggiornando un oggetto dominio pre-popolato ... Per questo motivo ho bisogno di chiamare il mio countryService per cercare l'oggetto Paese corretto. Voglio acquisire il 'Codice' da Dto e quindi utilizzare quel codice per cercare l'oggetto Paese corretto. – Galen

risposta

3

Utilizzando il suggerimento/di riferimento da Omu questo era il codice specifico per il problema.

public class CountryLookup : ExactValueInjection 
    { 
     private ICountryService countryservice; 

     public CountryLookup(ICountryService countryService) 
     { 
      this.countryService = countryService; 
     } 

     protected override bool TypesMatch(Type s, Type t) 
     { 
      return (s == typeof(string)) && (t == typeof (Country)); 

     } 
     protected override Object SetValue(object v) 
     { 
      if (v == null) 
       return null; 

      var country = countryService.LookupCode((string) v); 
      return country; 
     } 

     public override string SourceName() 
     { 
      return "CountryCode"; 
     } 

     public override string TargetName() 
     { 
      return "Country"; 
     }  
    } 

public Member InjectFromDto (MemberDto dto, Member source) 
{ 
    source = source.InjectFrom<UnflatLoopValueInjection>(dto) 
        .InjectFrom<CountryLookup>(dto); 
    return source; 
} 
+1

sì, questo dovrebbe funzionare (anche se non vedo dove si imposta il parametro di costruzione ICountryService), volevo solo che tu guardassi in un modo più generico, un'iniezione per ogni cosa – Omu

+0

Il parametro costruttore è impostato in questo caso attraverso Castle Windsor iniezione di dipendenza. È un po 'un punto di silenzio per la soluzione così come la chiamata di servizio di ricerca effettiva non è rilevante. – Galen

+0

Inoltre, prenderò in considerazione una soluzione generica per questo progetto usando i tuoi suggerimenti, grazie :) – Galen

0

È un framework che chiama il metodo setter? Nella maggior parte dei framework DI, lo standard è in lettere minuscole nel setMethod(). Solo una raccomandazione di prima scelta.

+0

Ti stai riferendo al metodo SetValue? In tal caso, fa parte del framework ValueInjecter. – Galen

+0

Nick, questo è .NET, non Java, lo standard .NET è il caso pascal per i nomi dei metodi, non il caso cammello. – Phill

3

unflattening sarebbe quello di fare questo:

entity.Country.Code <- dto.CountryCode 

quello che vi serve è:

entity.Country <- dto.CountryCode 

quindi la soluzione per voi sarebbe quella di ereditare un ExactValueInjection dove andresti da CountryCode a paese.

quello vi consiglio di fare è fare lo stesso che ho fatto nella demo dal vivo di un altro mio progetto http://awesome.codeplex.com

dove ho qualcosa di simile:

public class Entity 
    { 
     public int Id{get;set;} 
    } 
    public class Member : Entity 
    { 
     public Country Country{get;set;} 
    } 
    public class MemberDto : DtoWithId 
    { 
     public int? Country {get;set;} 
    } 

e utilizzare questi iniezioni per andare da entità a dto e ritorno

public class NullIntToEntity : LoopValueInjection 
     { 
      protected override bool TypesMatch(Type sourceType, Type targetType) 
      { 
       return sourceType == typeof(int?) && targetType.IsSubclassOf(typeof(Entity)); 
      } 

      protected override object SetValue(object sourcePropertyValue) 
      { 
       if (sourcePropertyValue == null) return null; 
       var id = ((int?) sourcePropertyValue).Value; 

       dynamic repo = IoC.Resolve(typeof(IRepo<>).MakeGenericType(TargetPropType)); 

       return repo.Get(id); 
      } 
     } 
//(you also need to have a generic repository, notice IRepo<>)  
    public class EntityToNullInt : LoopValueInjection 
     { 
      protected override bool TypesMatch(Type sourceType, Type targetType) 
      { 
       return sourceType.IsSubclassOf(typeof (Entity)) && targetType == typeof (int?); 
      } 

      protected override object SetValue(object o) 
      { 
       if (o == null) return null; 
       return (o as Entity).Id; 
      } 
     } 

queste iniezioni gestiranno non solo andando da int? a Paese e indietro, ma anche qualsiasi altro tipo che eredita Entità

+0

Questo commento porta alla risposta specifica al mio problema, ma non mostra la risposta esatta, che post malato. Può essere fatto +1 su come utile. – Galen