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的代码度量值。

标签: