关于Dapper的使用笔记3

1、默认的类型映射,直接以实体属性(或字段)映射到SQL中字段,(名称可以忽略大小写)

2、如果字段带下划线的,设置Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; 即可。

3、正因为有这个DefaultTypeMap默认的映射策略,所以,一般情况下,可以直接通过SQL查询,生成实体List.

4、Dapper还是以数据库为中心的思考问题模式,不同于Entity framework和nhibernate,提倡以实体到DB的思考问题方式。

5、Dapper在处理实体关联方面算是硬伤了,只能程序员自已根据DTO的模型去自已动手组装了。

附上代码

    /// <summary>

    /// 表示Dapper默认的类型映射策略

    /// Represents default type mapping strategy used by Dapper

    /// </summary>

    sealed partial class DefaultTypeMap : SqlMapper.ITypeMap

    {

        /// <summary>

        /// 要映射的实体,所有的字段

        /// </summary>

        private readonly List<FieldInfo> _fields;



        /// <summary>

        /// 要映射的实体,所有的属性

        /// </summary>

        private readonly List<PropertyInfo> _properties;



        /// <summary>

        /// 要映射的实体类型

        /// </summary>

        private readonly Type _type;



        /// <summary>

        /// 构造函数,创建缺省的类型映射策略

        /// Creates default type map

        /// </summary>

        /// <param name="type">Entity type</param>

        public DefaultTypeMap(Type type)

        {

            if (type == null)

                throw new ArgumentNullException("type");



            _fields = GetSettableFields(type);

            _properties = GetSettableProps(type);

            _type = type;

        }



        /// <summary>

        /// 获取属性的setter访问器

        /// </summary>

        /// <param name="propertyInfo"></param>

        /// <param name="type"></param>

        /// <returns></returns>

        internal static MethodInfo GetPropertySetter(PropertyInfo propertyInfo, Type type)

        {

            return propertyInfo.DeclaringType == type ?

                propertyInfo.GetSetMethod(true) :

                propertyInfo.DeclaringType.GetProperty(

                   propertyInfo.Name,

                   BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,

                   Type.DefaultBinder,

                   propertyInfo.PropertyType,

                   propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray(),

                   null).GetSetMethod(true);

        }



        /// <summary>

        /// 获取某类型所有可写(有set,包括私有)的成员属性

        /// </summary>

        /// <param name="t"></param>

        /// <returns></returns>

        internal static List<PropertyInfo> GetSettableProps(Type t)

        {

            return t

                  .GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)

                  .Where(p => GetPropertySetter(p, t) != null)

                  .ToList();

        }



        /// <summary>

        /// 获取某类型所有的成员字段

        /// </summary>

        /// <param name="t"></param>

        /// <returns></returns>

        internal static List<FieldInfo> GetSettableFields(Type t)

        {

            return t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToList();

        }



        /// <summary>

        /// 获取最佳的成员构造器,优先顺序:public的构造器0, 其它构造器1, private的构造器2,然后再按参数匹配

        /// Finds best constructor

        /// </summary>

        /// <param name="names">DataReader column names</param>

        /// <param name="types">DataReader column types</param>

        /// <returns>Matching constructor or default one</returns>

        public ConstructorInfo FindConstructor(string[] names, Type[] types)

        {

            var constructors = _type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

            foreach (ConstructorInfo ctor in constructors.OrderBy(c => c.IsPublic ? 0 : (c.IsPrivate ? 2 : 1)).ThenBy(c => c.GetParameters().Length))

            {

                ParameterInfo[] ctorParameters = ctor.GetParameters();

                if (ctorParameters.Length == 0)

                    return ctor;



                if (ctorParameters.Length != types.Length)

                    continue;



                int i = 0;

                for (; i < ctorParameters.Length; i++)

                {

                    if (!String.Equals(ctorParameters[i].Name, names[i], StringComparison.OrdinalIgnoreCase))

                        break;

                    if (types[i] == typeof(byte[]) && ctorParameters[i].ParameterType.FullName == SqlMapper.LinqBinary)

                        continue;

                    var unboxedType = Nullable.GetUnderlyingType(ctorParameters[i].ParameterType) ?? ctorParameters[i].ParameterType;

                    if (unboxedType != types[i]

                        && !(unboxedType.IsEnum && Enum.GetUnderlyingType(unboxedType) == types[i])

                        && !(unboxedType == typeof(char) && types[i] == typeof(string)))

                        break;

                }



                if (i == ctorParameters.Length)

                    return ctor;

            }



            return null;

        }



        /// <summary>

        /// 查找带ExplicitConstructorAttribute特性标识的构造器

        /// Returns the constructor, if any, that has the ExplicitConstructorAttribute on it.

        /// </summary>

        public ConstructorInfo FindExplicitConstructor()

        {

            var constructors = _type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

            var withAttr = constructors.Where(c => c.GetCustomAttributes(typeof(ExplicitConstructorAttribute), true).Length > 0).ToList();



            if (withAttr.Count == 1)

            {

                return withAttr[0];

            }



            return null;

        }



        /// <summary>

        /// 根据构造函数和列名

        /// Gets mapping for constructor parameter

        /// </summary>

        /// <param name="constructor">Constructor to resolve</param>

        /// <param name="columnName">DataReader column name</param>

        /// <returns>Mapping implementation</returns>

        public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)

        {

            var parameters = constructor.GetParameters();



            //注意构造器参数名与列名是相同的(忽略大小写)

            return new SimpleMemberMap(columnName, parameters.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase)));

        }



        /// <summary>

        /// 为某列找到映射关系,返回IMemberMap

        /// Gets member mapping for column

        /// </summary>

        /// <param name="columnName">DataReader column name</param>

        /// <returns>Mapping implementation</returns>

        public SqlMapper.IMemberMap GetMember(string columnName)

        {

            //优先找与列名相同的属性名(优先找大小写相同的,再找不同的)。

            var property = _properties.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))

               ?? _properties.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase));



            //如果找不到,就尝试去掉列名下划线,再找一次。

            if (property == null && MatchNamesWithUnderscores)

            {

                property = _properties.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.Ordinal))

                    ?? _properties.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.OrdinalIgnoreCase));

            }



            //如果找到就返回一个成员映射对象

            if (property != null)

                return new SimpleMemberMap(columnName, property);



            //如果没有找到匹配的属性,就找DomainObject.Field,按照上面的套路再找一次。

            var field = _fields.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))

               ?? _fields.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase));



            if (field == null && MatchNamesWithUnderscores)

            {

                field = _fields.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.Ordinal))

                    ?? _fields.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.OrdinalIgnoreCase));

            }



            if (field != null)

                return new SimpleMemberMap(columnName, field);



            return null;

        }

        /// <summary>

        /// 按列名匹配属性时,忽略下划线(有些时习惯在数据库中使用下划线)。

        /// Should column names like User_Id be allowed to match properties/fields like UserId ?

        /// </summary>

        public static bool MatchNamesWithUnderscores { get; set; }

    }

 

你可能感兴趣的:(APP)