Могу ли я настроить AutoMapper для чтения из имен пользовательских столбцов при сопоставлении из IDataReader? - PullRequest
5 голосов
/ 17 июня 2010

Код Psuedo для конфигурации сопоставления (как показано ниже) невозможен, так как лямбда-код позволяет нам получать доступ только к типу IDataReader, тогда как при фактическом сопоставлении AutoMapper будет попадать в каждую «ячейку» каждой IDataRecord, тогда как IDataReader.Read() == true:

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

Может кто-нибудь придумать, как сделать это, используя конфигурацию AutoMapper во время выполнения или просто какой-нибудь другой динамический подход, который удовлетворяет требованиям ниже.

Требуется поддерживать все входящие IDataReader, которые могут иметь имена столбцов, которые не соответствуют именам свойств MyDTO, и не существует соглашения об именовании, на которое я могу положиться. Вместо этого мы попросим пользователя во время выполнения сопоставить ожидаемые имена столбцов с фактическими именами столбцов, найденными в IDataReader через IDataReader.GetSchemaTable().

1 Ответ

3 голосов
/ 17 июня 2010

Я не знаю об автоматическом преобразователе, но я сопоставляю средство чтения данных с объектами, используя ValueInjecter , например:

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

и DataReaderInjection (что-то вроде ValueResolver для 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);
            }
        }
    }

вы можете использовать это для ввода значений из IDataReader в любой тип объекта


ок, поэтому в соответствии с вашими требованиями, я думаю, это должно быть так:
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]);
                }
            }
        }

здесь я использовал GetSchemaTable, как вы и хотели:)

Хорошо, если вы хотите передать некоторые вещи в инъекцию, вы можете сделать это разными способами, вот как:

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

вот подсказка (для конструктора с параметрами way)

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