2010-06-17 19 views
5

Pseudo codice per la configurazione di mapping (come sotto) non è possibile in quanto il lambda ci permette solo l'accesso Tipo IDataReader, wheras quando in realtà la mappatura, automapper raggiungerà in ogni "cella" di ogni IDataRecord mentre IDataReader.Read() == true:Posso configurare AutoMapper per leggere dai nomi di colonne personalizzate durante il mapping da IDataReader?

var mappingConfig = Mapper.CreateMap<IDataReader, IEnumerable<MyDTO>>(); 
mappingConfig.ForMember(
    destination => destination.???, 
    options => options.MapFrom(source => source.???)); 

Qualcuno può pensare a un modo per farlo utilizzando la configurazione di AutoMapper in fase di esecuzione o solo qualche altro approccio dinamico che soddisfi i requisiti di seguito.

L'esigenza è di supportare qualsiasi IDataReader in arrivo che potrebbe avere nomi di colonna che non corrispondono ai nomi di proprietà di MyDTO e non esiste alcuna convenzione di denominazione su cui fare affidamento. Invece chiederemo all'utente in fase di runtime di fare un riferimento incrociato ai nomi delle colonne attese con i nomi delle colonne effettivi trovati nello IDataReader tramite IDataReader.GetSchemaTable().

risposta

3

Non so circa automapper ma sono mappatura DataReader per oggetti utilizzando il ValueInjecter in questo modo:

while (dr.Read()) 
{ 
    var o = new User(); 
    o.InjectFrom<DataReaderInjection>(dr); 
    return o; 
} 

e il DataReaderInjection (qualcosa come ValueResolver per Automapper)

public class DataReaderInjection : KnownSourceValueInjection<IDataReader> 
    { 
     protected override void Inject(IDataReader source, object target, PropertyDescriptorCollection targetProps) 
     { 
      for (var i = 0; i < source.FieldCount; i++) 
      { 
       var activeTarget = targetProps.GetByName(source.GetName(i), true); 
       if (activeTarget == null) continue; 

       var value = source.GetValue(i); 
       if (value == DBNull.Value) continue; 

       activeTarget.SetValue(target, value); 
      } 
     } 
    } 
si

può usare questo per iniettare valori da un IDataReader a qualsiasi tipo dell'oggetto


ok, quindi secondo il vostro req uirements, credo che dovrebbe essere simile a questo:

public class DataReaderInjection : KnownSourceValueInjection<IDataReader> 
     { 
      protected override void Inject(IDataReader source, object target, PropertyDescriptorCollection targetProps) 
      { 
       var columns = source.GetSchemaTable().Columns; 
       for (var i = 0; i < columns.Count; i++) 
       { 
        var c = columns[i]; 

        var targetPropName = c.ColumnName; //default is the same as columnName 

        if (c.ColumnName == "Foo") targetPropName = "TheTargetPropForFoo"; 
        if (c.ColumnName == "Bar") targetPropName = "TheTargetPropForBar"; 
        //you could also create a dictionary and use it here 

        var targetProp = targetProps.GetByName(targetPropName); 
        //go to next column if there is no such property in the target object 
        if (targetProp == null) continue; 

        targetProp.SetValue(target, columns[c.ColumnName]); 
       } 
      } 
     } 

qui ho usato GetSchemaTable, proprio come volevi :)


ok, se si vuole passare un po 'di roba per l'iniezione, si può fare in molti modi, ecco come:

o.InjectFrom(new DataReaderInjection(stuff), dr); 
//you need a constructor with parameters for the DataReaderInjection in this case 

var ri = new DataReaderInjection(); 
ri.Stuff = stuff; 
o.InjectFrom(ri, dr); 
//you need to add a property in this case 

ecco un suggerimento (per il costruttore con i parametri modo)

public class DataReaderInjection : KnownSourceValueInjection<IDataReader> 
    { 
     private IDictionary<string, string> stuff; 
     public DataReaderInjection(IDictionary<string,string> stuff) 
     { 
      this.stuff = stuff; 
     } 
        protected override void Inject(
... 
+0

+1 per una risposta molto interessante. Tuttavia non soddisfa (ancora) il requisito in quanto si aspetta ancora che il nome della "colonna" corrisponda al nome della proprietà. Grazie comunque per l'Head-up su ValueInjecter. – rohancragg

+2

@rohancragg hai tutti i nomi delle proprietà dall'oggetto (targetProps) e puoi ottenere tutti i nomi dal datareader (source.GetName (theName)), quindi puoi modificarlo in base alle tue esigenze – Omu

+1

@rohancragg Ho modificato la mia domanda, penso che in questo modo dovrebbe funzionare (non l'ho provato, ma lo spero) – Omu