2010-06-17 34 views
5

Code Psuedo pour la configuration de la cartographie (comme ci-dessous) n'est pas possible car le type lambda nous permet d'accéder uniquement IDataReader, wheras alors qu'en réalité, la cartographie, AutoMapper atteindra dans chaque "cellule" de chaque IDataRecord en IDataReader.Read() == true:Puis-je configurer AutoMapper pour lire les noms de colonnes personnalisés lors du mappage à partir d'IDataReader?

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

Quelqu'un peut-il penser à un moyen de le faire en utilisant la configuration AutoMapper au moment de l'exécution ou juste une autre approche dynamique qui répond aux exigences ci-dessous.

L'exigence est de prendre en charge tous les IDataReader entrants qui peuvent avoir des noms de colonne qui ne correspondent pas aux noms de propriété de MyDTO et il n'y a pas de convention de dénomination sur laquelle je peux compter. Au lieu de cela, nous demanderons à l'utilisateur lors de l'exécution de renvoyer les noms de colonne attendus avec les noms de colonne réels trouvés dans le IDataReader via IDataReader.GetSchemaTable().

Répondre

3

Je ne sais pas automapper mais je suis cartographie datareader à des objets en utilisant le ValueInjecter comme ceci:

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

et la DataReaderInjection (quelque chose comme ValueResolver pour 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); 
      } 
     } 
    } 

vous peut l'utiliser pour injecter des valeurs d'un IDataReader à tout type de l'objet


ok, donc en fonction de votre req uirements, je pense qu'il devrait être comme ceci:

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

ici je GetSchemaTable, comme vous vouliez :)


ok, si vous voulez passer des choses à l'injection, vous pouvez faire à bien des égards, voici comment:

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 

est ici une touche (pour le constructeur avec le mode paramètres)

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 pour une réponse très intéressante. Cependant, il ne répond pas (encore) à l'exigence car il s'attend toujours à ce que le nom de la colonne corresponde au nom de la propriété. Merci pour le heads-up sur ValueInjecter de toute façon. – rohancragg

+2

@rohancragg vous avez tous les noms de propriété de l'objet (targetProps) et vous pouvez obtenir tous les noms de la tête de lecture (source.GetName (theName)), de sorte que vous pouvez le modifier en fonction de vos besoins – Omu

+1

@rohancragg J'ai modifié ma question, je pense que cette façon devrait fonctionner (je ne l'ai pas essayé, mais je l'espère) – Omu