Использование AutoMapper для простых свойств объекта в массив SqlParameters - PullRequest
1 голос
/ 14 марта 2012

Я начал изучать AutoMapper и у меня есть сценарий «управляемый данными» ... У меня есть код для заполнения свойств сущностей из SqlDataReader на основе некоторой «информации о схеме», которую я передаю ...

Далее я хочу взять свойства Entity ... и затем, основываясь на имеющейся у меня информации Schema, создать набор SqlParameters из значений объекта ...

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

Я набросал следующее ... Я пытаюсь использовать TypeConverters и регистрирую их заранее, но когда я выполняю фактическую операцию map.ForMember (), она выдает ошибку с жалобой

«Настраиваемая конфигурация для элементов поддерживается только для отдельных элементов верхнего уровня для типа.»

Несколько вариантов, которые я пробовал и не увенчался успехом...

(1) пробовал гораздо более простые версии ... (2) пытался использовать механизм ConstructUsing (), и тогда целью операции на самом деле является свойство SqlParameter. [[[Value]]] (большинствоскорее всего, «правильный» путь в правильном мышлении AutoMapper ??) (3) пытался предварительно создать список целей и затем «найти» соответствующий параметр - но установка значения .Value все еще оставалась недостающей частью этого уравнения..

Будучи новичком в AutoMapper, я ожидал несколько проблем, но потратил достаточно времени на это и не нашел ничего очевидного ... кажется, что это должен быть простой вариант использования для фреймворка ... Iдолжно быть пропущено что-то очевидное ...

class Program
{
    static void Main(string[] args)
    {
        // Drive it by some data... Say some mapping info we have from elsewhere...
        var myMappingPairs = new List<MyMappingInfo>()
        {
            new MyMappingInfo() { PropertyName = "MyGuidProperty", ParameterName = "Param00" },
            new MyMappingInfo() { PropertyName = "MyStringProperty", ParameterName = "Param01" },
            new MyMappingInfo() { PropertyName = "MyInt16Property", ParameterName = "Param02" },
            new MyMappingInfo() { PropertyName = "MyInt32Property", ParameterName = "Param03" },
            new MyMappingInfo() { PropertyName = "MyInt64Property", ParameterName = "Param04" }
        };

        // We can try to register these, but the sytax isn't clear to me yet...
        Mapper.CreateMap<Guid, SqlParameter>().ConvertUsing<GuidToSqlParameterConverter>();
        Mapper.CreateMap<String, SqlParameter>().ConvertUsing<StringToSqlParameterConverter>();
        Mapper.CreateMap<Int16, SqlParameter>().ConvertUsing<Int16ToSqlParameterConverter>();
        Mapper.CreateMap<Int32, SqlParameter>().ConvertUsing<Int32ToSqlParameterConverter>();
        Mapper.CreateMap<Int64, SqlParameter>().ConvertUsing<Int64ToSqlParameterConverter>();

        // Next we'll build our mapping from the "pairings"...
        var map = Mapper.CreateMap<MySourceEntity, List<SqlParameter>>();

        foreach (var mappingPair in myMappingPairs)
        {
            map.ForMember
                (
                    destination => destination,
                    options => options.ResolveUsing<PropertyNameResolver>().FromMember
                        (
                            mappingPair.PropertyName    // <-- Data Driven Property Name...
                        )
                );
        }

        // Create a test entity...
        var entity = new MySourceEntity() 
        {
            MyGuidProperty = Guid.NewGuid(), 
            MyStringProperty = "Hello AutoMapper",
            MyInt16Property = Int16.MaxValue,
            MyInt32Property = Int32.MaxValue,
            MyInt64Property = Int64.MaxValue
        };

        // Map it...
        var values = Mapper.Map<MySourceEntity, object[]>
            (
                entity
            );

    }
}

public class MySourceEntity
{
    public string MyStringProperty { get; set; }
    public DateTime? MyDateTimeProperty { get; set; }
    public Byte? MyByteProperty { get; set; }
    public Int16? MyInt16Property { get; set; }
    public Int32? MyInt32Property { get; set; }
    public Int64? MyInt64Property { get; set; }
    public Guid? MyGuidProperty { get; set; }

    public List<String> ThisShouldntGetMapped { get; set; }
    public StringBuilder NorShouldThis { get; set; }
}

public class MyMappingInfo
{
    public String PropertyName { get; set; }
    public String ParameterName { get; set; }
    public SqlDbType SqlDbType { get; set; }
}

public class GuidToSqlParameterConverter : AutoMapper.ITypeConverter<Guid, SqlParameter>
{
    public SqlParameter Convert(ResolutionContext context)
    {
        if (context.IsSourceValueNull)
        {
            return new SqlParameter()
            {
                ParameterName = "GuidParam",
                SqlDbType = SqlDbType.UniqueIdentifier,
                Value = DBNull.Value
            };
        }
        else
        {
            return new SqlParameter()
            {
                ParameterName = "GuidParam",
                SqlDbType = SqlDbType.UniqueIdentifier,
                Value = context.SourceValue
            };
        }
    }
}
public class StringToSqlParameterConverter : AutoMapper.ITypeConverter<string, SqlParameter>
{
    public SqlParameter Convert(ResolutionContext context)
    {
        if (context.IsSourceValueNull)
        {
            return new SqlParameter()
            {
                ParameterName = "StringParam",
                SqlDbType = SqlDbType.NVarChar,
                Value = DBNull.Value
            };
        }
        else
        {
            return new SqlParameter()
            {
                ParameterName = "StringParam",
                SqlDbType = SqlDbType.NVarChar,
                Value = context.SourceValue
            };
        }
    }
}

public class Int16ToSqlParameterConverter : AutoMapper.ITypeConverter<Int16, SqlParameter>
{
    public SqlParameter Convert(ResolutionContext context)
    {
        if (context.IsSourceValueNull)
        {
            return new SqlParameter()
            {
                ParameterName = "Int16Param",
                SqlDbType = SqlDbType.SmallInt,
                Value = DBNull.Value
            };
        }
        else
        {
            return new SqlParameter()
            {
                ParameterName = "Int16Param",
                SqlDbType = SqlDbType.SmallInt,
                Value = context.SourceValue
            };
        }
    }
}

public class Int32ToSqlParameterConverter : AutoMapper.ITypeConverter<Int32, SqlParameter>
{
    public SqlParameter Convert(ResolutionContext context)
    {
        if (context.IsSourceValueNull)
        {
            return new SqlParameter()
            {
                ParameterName = "Int32Param",
                SqlDbType = SqlDbType.Int,
                Value = DBNull.Value
            };
        }
        else
        {
            return new SqlParameter()
            {
                ParameterName = "Int32Param",
                SqlDbType = SqlDbType.Int,
                Value = context.SourceValue
            };
        }
    }
}

public class Int64ToSqlParameterConverter : AutoMapper.ITypeConverter<Int64, SqlParameter>
{
    public SqlParameter Convert(ResolutionContext context)
    {
        if (context.IsSourceValueNull)
        {
            return new SqlParameter()
            {
                ParameterName = "Int64Param",
                SqlDbType = SqlDbType.BigInt,
                Value = DBNull.Value
            };
        }
        else
        {
            return new SqlParameter()
            {
                ParameterName = "Int64Param",
                SqlDbType = SqlDbType.BigInt,
                Value = context.SourceValue
            };
        }
    }
}

}

Я хотел бы знать, будет ли полученный в результате код выполнения в AutoMapper работать лучше, чем, скажем:

    static IDictionary<string, object> GetDictionaryFromObject(object obj)
    {
        if (obj == null) return new Dictionary<string, object>();
        return obj.GetType().GetProperties()
                   .ToDictionary(p => p.Name,
                                 p => p.GetValue(obj, null) ?? DBNull.Value);
    }  

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...