• Dapper


    Dapper目前的Bug以已经很少了。可以被正式的项目中使用。所以算是一个值得使用的ORM了。

    github上的代码有段时间没有更新了,也懒得等官方去修正,所以自己动手丰衣足食吧。个人修改后的代码在点这里下载。懒得读下文的直接下载更新包吧。修改的地方不多,并不影响官方的更新。

    大体的BUG有这些:

    Bug1:Mysql和Mssql中的Bit类型的问题

    直接修改代码,代码的第795行,增加以下代码。

    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
            [Obsolete("This method is for internal usage only", false)]
            public static bool ReadBool(object value)
            {
                if (value.GetType() != typeof(bool))
                {
                    return Convert.ToBoolean(value);
                }
                else
                    return (bool)value;
            }
    

    代码的第1204行增加这一段代码。

        if (memberType == typeof(Boolean))
                        {
                            il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod("ReadBool", BindingFlags.Static | BindingFlags.Public), null); 
                        }
    

    错误的原因就是之前的代码对于Bool未做处理,所以导致在Bit字段被当成UInt64处理而在Map的布尔时候类型转化异常。


    BUG2:其实这个并不属于BUG,只是不同的数据库对应的类型不同。比如Oracle数据库中的VARCHAR2字段对应的 DbType.AnsiString。侧用以下代码来实例化字段即可。有些版本上没有这个部分。如没有加上即可。

      public sealed class DbString
        {
            public DbString() { Length = -1; }
    
            public bool IsAnsi { get; set; }
          
            public bool IsFixedLength { get; set; }
    
            public int Length { get; set; }
    
            public string Value { get; set; }
    
            public void AddParameter(IDbCommand command, string name)
            {
                if (IsFixedLength && Length == -1)
                {
                    throw new InvalidOperationException("If specifying IsFixedLength,  a Length must also be specified");
                }
                var param = command.CreateParameter();
                param.ParameterName = name;
                param.Value = (object)Value ?? DBNull.Value;
                if (Length == -1 && Value != null && Value.Length <= 4000)
                {
                    param.Size = 4000;
                }
                else
                {
                    param.Size = Length;
                }
                param.DbType = IsAnsi ? (IsFixedLength ? DbType.AnsiStringFixedLength : DbType.AnsiString) : (IsFixedLength ? DbType.StringFixedLength : DbType.String);
                command.Parameters.Add(param);
            }
        }
    

    操作代码:

                IDbCommand idc = new OracleCommand();
                DbString ds = new DbString();
                ds.IsAnsi = true;
                ds.Value = "";
                ds.AddParameter(idc, "@Content");
    

    不少喜欢POCO以及IRepositories的朋友可以装这个扩展.

    using System;
    using System.Linq;
    using System.Data;
    using System.Text;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    
    namespace SqlMapper
    {
    
        [AttributeUsage(AttributeTargets.Property)]
        public class KeyAttribute : Attribute
        {
        }
    
        public static class DapperExtensions
        {
            public static void Insert<T>(this IDbConnection connection, T entityvalue)
            {
                Insert(connection, null, entityvalue);
            }
    
            public static void Insert<T>(this IDbConnection connection, string sql, T entityvalue)
            {
                var name = entityvalue.GetType().Name;
                var sb = new StringBuilder(sql);
                if (sql == null)
                {
                    sb.AppendFormat("insert into {0}", name);
                    sb.Append(" (");
                    BuildInsertParameters(entityvalue, sb);
                    sb.Append(") values (");
                    BuildInsertValues(entityvalue, sb);
                    sb.Append(")");
    
                }
                connection.Execute(sb.ToString(), entityvalue);
            }
    
            public static int Update<T>(this IDbConnection connection, T entityvalue)
            {
                return Update(connection, null, entityvalue);
            }
    
            public static int Update<T>(this IDbConnection connection, string sql, T entityvalue)
            {
                var idProps = GetIdProperties(entityvalue);
                if (idProps.Count() == 0)
                    throw new ArgumentException("Entity must have at least one [Key] property");
    
                var name = entityvalue.GetType().Name;
    
                var sb = new StringBuilder(sql);
                if (sql == null)
                    sb.AppendFormat("update {0}", name);
    
                sb.AppendFormat(" set ");
                BuildUpdateSet(entityvalue, sb);
                sb.Append(" where ");
                BuildWhere(sb, idProps.ToArray());
    
                return connection.Execute(sb.ToString(), entityvalue);
            }
    
            public static int Delete<T>(this IDbConnection connection, T entityvalue)
            {
                return Delete(connection, null, entityvalue);
            }
    
            public static int Delete<T>(this IDbConnection connection, string sql, T entityvalue)
            {
                var idProps = typeof(T).IsAnonymousType() ?
                    GetAllProperties(entityvalue) :
                    GetIdProperties(entityvalue);
    
                if (idProps.Count() == 0)
                    throw new ArgumentException("Entity must have at least one [Key] property");
    
                var name = entityvalue.GetType().Name;
    
                var sb = new StringBuilder(sql);
                if (sql == null)
                    sb.AppendFormat("delete from {0}", name);
    
                sb.Append(" where ");
                BuildWhere(sb, idProps);
    
                return connection.Execute(sb.ToString(), entityvalue);
            }
    
            private static void BuildUpdateSet(object entityToUpdate, StringBuilder sb)
            {
                var nonIdProps = GetNonIdProperties(entityToUpdate).ToArray();
    
                for (var i = 0; i < nonIdProps.Length; i++)
                {
                    var property = nonIdProps[i];
    
                    sb.AppendFormat("{0} = @{1}", property.Name, property.Name);
                    if (i < nonIdProps.Length - 1)
                        sb.AppendFormat(", ");
                }
            }
    
            private static void BuildWhere(StringBuilder sb, IEnumerable<PropertyInfo> idProps)
            {
                for (var i = 0; i < idProps.Count(); i++)
                {
                    sb.AppendFormat("{0} = @{1}", idProps.ElementAt(i).Name, idProps.ElementAt(i).Name);
                    if (i < idProps.Count() - 1)
                        sb.AppendFormat(" and ");
                }
            }
    
            private static void BuildInsertValues(object entityToInsert, StringBuilder sb)
            {
                var props = GetAllProperties(entityToInsert);
    
                for (var i = 0; i < props.Count(); i++)
                {
                    var property = props.ElementAt(i);
                    if (property.GetCustomAttributes(true).Where(a => a is KeyAttribute).Any()) continue;
                    sb.AppendFormat("@{0}", property.Name);
                    if (i < props.Count() - 1)
                        sb.Append(", ");
                }
            }
    
            private static void BuildInsertParameters(object entityToInsert, StringBuilder sb)
            {
                var props = GetAllProperties(entityToInsert);
    
                for (var i = 0; i < props.Count(); i++)
                {
                    var property = props.ElementAt(i);
                    if (property.GetCustomAttributes(true).Where(a => a is KeyAttribute).Any()) continue;
                    sb.Append(property.Name);
                    if (i < props.Count() - 1)
                        sb.Append(", ");
                }
            }
    
            private static IEnumerable<PropertyInfo> GetAllProperties(object entity)
            {
                return entity.GetType().GetProperties();
            }
    
            private static IEnumerable<PropertyInfo> GetNonIdProperties(object entity)
            {
                return GetAllProperties(entity).Where(p => p.GetCustomAttributes(true).Any(a => a is KeyAttribute) == false);
            }
    
            private static IEnumerable<PropertyInfo> GetIdProperties(object entity)
            {
                return GetAllProperties(entity).Where(p => p.GetCustomAttributes(true).Any(a => a is KeyAttribute));
            }
        }
    
        public static class TypeExtension
        {
            public static Boolean IsAnonymousType(this Type type)
            {
                if (type == null) return false;
    
                var hasCompilerGeneratedAttribute = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Count() > 0;
                var nameContainsAnonymousType = type.FullName.Contains("AnonymousType");
                var isAnonymousType = hasCompilerGeneratedAttribute && nameContainsAnonymousType;
    
                return isAnonymousType;
            }
        }
    }
    

    于是数据库的操作就简化为了这样。从这里可以看出其实Dapper在扩展方面完全要超过PetaPoco,并且更加适合DIY。对于关于数据库主从分离,读写分离以及扩展可以参考我上篇的博文。点此进入

                var dogs = conn.Query<Dog>("select * from dog where id = 1", null, null, true, 30, CommandType.Text).SingleOrDefault();
                conn.Insert<Dog>(dogs);
                conn.Update<dogs>(dogs);
                conn.Delete<Dog>(dogs);
    

    Dapper简单并且高效,效率接近于手写的IDateReader,高于DateTable,所以对于效率极其推崇的可以使用下。

    附Dapper的代码度量值。

  • 相关阅读:
    王歆瑶20191128-1 总结
    王歆瑶 20191121-1 每周例行报告
    王歆瑶20191114-1 每周例行报告
    王歆瑶20191107-1 每周例行报告
    王歆瑶20191031-1 每周例行报告
    王歆瑶20191024-1 每周例行报告
    王歆瑶20191017-1 每周例行报告
    王歆瑶20191010-2 每周例行报告
    王歆瑶20190919-4 单元测试,结对
    LeetCode 11 盛水最多的容器
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/5992198.html
Copyright © 2020-2023  润新知