dapper query 参数怎么用参数化查询

Edit: Using the Execute method instead of the Query/QueryMultiple methods, my OUT_SUCCESS parameter now has an AttachedParam with with an OracleParameter that has the returned value. So this would work if, for instance, I only needed to retrieve non-cursors parameters. Then I could use Execute for procedures with all non-cursor output parameters and Query/QueryMultiple for procedures with only cursor output parameters. But what if I need to call a stored procedure that has both cursor and non-cursor output parameters, as is often the case?
Using Dapper.NET and the
I have successfully returned and mapped multiple IN OUT REF CURSORs, but I cannot get the value a single OUT parameter.
For instance, I am trying to call a stored procedure with the following spec:
PROCEDURE DO_SOMETHING (
OUT_SUCCESS
OUT VARCHAR2
for which I have created a corresponding C# class to model it, which contains methods to get the OracleDynamicParameters, the CommandText, and so forth, and also includes an auto-implemented property for each parameter
public class DO_SOMETHING {
... //code to return parameters, etc
public string OUT_SUCCESS { }
and I have tried all of the following syntax:
using (var gridReader = Connection.mandText(), param: nModel.DynamicParameters(), commandType: mandType()))
OUT_SUCCESS = ((OracleDynamicParameters)Model.DynamicParameters()).Get&string&("OUT_SUCCESS"); // 1
OUT_SUCCESS = gridReader.Read&string&().Single(); //2
OUT_SUCCESS = gridReader.Read&DO_SOMETHING&().Single().OUT_SUCCESS; //3
but none of them work:
The AttachedParam is null for the parameter with name "OUT_SUCCESS" (although I can see the parameter exists)
The gridReader reports that the "sequence contains no elements", probably because it has no idea how to read a string out of the response.
This one seems the most promising - InvalidArgumentException: the gridReader advises me that "When using the multi-mapping APIs ensure you set the splitOn param if you have keys other than Id", but I'm not really sure how this is pertinent to my problem.
By the way, I do know that the procedure is successfully executing because ODP.NET does not produce an exception and I see the resulting rows persisted in the database.
I don't know how to proceed, but I'd really like to use Dapper, as this is the last remaining hurdle to climb. Any help is always appreciated.
解决方案 Close the connection, then read the output parameter.
本文地址: &
编辑:使用执行方法,而不是查询 /
QueryMultiple 的方法,我的 OUT_SUCCESS 参数现在有一个 AttachedParam 与一个的OracleParameter 有返回值。因此这将工作,如果,例如,我的仅的检索非游标参数需要的。然后,我可以使用执行与所有非游标输出参数的程序和查询 /
QueryMultiple 与仅的指针输出参数的过程。但是,如果我需要调用存储过程具有双方光标和非游标输出参数,这是常有的情况?
使用 Dapper.NET 和我已经顺利返回并映射多个 IN OUT
REF CURSOR
S,但我不能获得价值单一 OUT 参数。
例如,我试图调用存储过程具有以下规范:
程序DO_SOMETHING(
OUT_SUCCESS OUT VARCHAR2
为此我创建了一个相应的C#类来模拟它,它包含的方法来获得 OracleDynamicParameters 的的CommandText ,系统等等,并且还包括自动实现的属性的对于每个参数的
公共类DO_SOMETHING {
... // code返回参数等
公共字符串OUT_SUCCESS {获得;组; }
和我已经尝试了所有的语法如下的:
使用(VAR gridReader = Connection.QueryMultiple(mandText(),参数:nModel.DynamicParameters(),命令类型:mandType()))
OUT_SUCCESS =((OracleDynamicParameters)Model.DynamicParameters())获取<字符串>(“OUT_SUCCESS”); // 1
OUT_SUCCESS = gridReader.Read<字符串>()单()。 // 2
OUT_SUCCESS = gridReader.Read< DO_SOMETHING>()单()OUT_SUCCESS。 // 3
但他们没有工作:
的 AttachedParam 是空与名称的参数“OUT_SUCCESS”(虽然我能看到的参数存在)
的 gridReader 报道说,“序列不包含任何元素”,可能是因为它不知道如何读一个串出的响应。
在这其中似乎是最有前途的 -
InvalidArgumentException :在 gridReader 建议我说:“当使用多映射的API确保您设置splitOn参数,如果你有钥匙比ID“等,但我真的不知道这是怎么有关我的问题。
顺便说一句,我不知道该程序已成功执行,因为ODP.NET不会产生异常,我看到的结果行保留在数据库中。
我不知道如何着手,但我真的很喜欢用小巧精致的,因为这是最后剩下的障碍攀升。任何帮助总是AP preciated。
解决方案 关闭连接,然后读取输出参数。
本文地址: &
扫一扫关注官方微信技术交流学习或者有任何问题欢迎加群 : &
标签:&&&在上次的扩展中,有朋友对代码和性能提出了一些批评。因此在今天扩展前我先说明:我遇到问题,是先解决,再谈优化,如果问题都不能解决,何来优化。所以在全部扩展完成之后,我会进行一次代码重构和一些性能优化(当然是在自己技术能力范围内的哈)所以暂时我们先放下代码和性能问题,先着手解决问题。
喜闻乐见的扩展又开始了GO
今天目标:查询扩展想到组装条件查询语句,开始想的是定义类,用树形结构来表示每一个条件单元(意思是:括号包含的条件,例如:where
(id&&‘‘))但是想到这样处理后,其实在编码使用上会觉得别扭(反正我不习惯),我决定要用括号时自己调用方法直接组装,这样也灵活,逻辑也不复杂。
查询少不了操作符,所以有了如下几个类
枚举:OperationMethod,定义SQL中操作符
using System.Collections.G
using System.L
using System.T
namespace DapperEx
/// &summary&
/// SQL操作符
/// &/summary&
public enum OperationMethod
/// &summary&
/// &/summary&
Equal = 1,
/// &summary&
/// &/summary&
/// &summary&
/// &/summary&
Greater = 3,
/// &summary&
/// 小于等于
/// &/summary&
LessOrEqual = 4,
/// &summary&
/// 大于等于
/// &/summary&
GreaterOrEqual = 5,
/// &summary&
/// 包含%-%
/// &/summary&
Contains = 6,
/// &summary&
/// 开始包含-%
/// &/summary&
StartsWith = 7,
/// &summary&
/// 结束包含%-
/// &/summary&
EndsWith = 8,
/// &summary&
/// &/summary&
/// &summary&
/// 不等于
/// &/summary&
NotEqual = 10,
}View Code
排序类:QueryOrder,用于排序处理
using System.Collections.G
using System.L
using System.T
namespace DapperEx
/// &summary&
/// &/summary&
public class QueryOrder
/// &summary&
/// 排序字段
/// &/summary&
public virtual string Field { get; set; }
/// &summary&
/// 是否倒序
/// &/summary&
public virtual bool IsDesc { get; set; }
}View Code
现在,我们思考一个问题:Dapper的参数化查询是这样:请注意后面的参数,是一个匿名类,如果要使用这样的查询,我们就必须对参数动态的创建类,如果动态对参数创建类,我们用emit
定义类:DynamicPropertyModel,此类用于保存每一个动态创建的参数的名称和类型
using System.Collections.G
using System.L
using System.T
namespace DapperEx
/// &summary&
/// 用于动态生成类的一个属性
/// &/summary&
public class DynamicPropertyModel
/// &summary&
/// 属性名称
/// &/summary&
public string Name { get; set; }
/// &summary&
/// 属性类型
/// &/summary&
public Type PropertyType { get; set; }
}View Code
定义动态创建类:CustomDynamicBuilder,用于动态创建参数类
using System.Collections.G
using System.L
using System.R
using System.Reflection.E
using System.T
namespace DapperEx
public class CustomDynamicBuilder
/// &summary&
/// 动态的创建一个类
/// &/summary&
/// &param name="className"&&/param&
/// &param name="lm"&&/param&
/// &returns&&/returns&
public static Type DynamicCreateType(string className, IList&DynamicPropertyModel& lm)
//动态创建程序集
AssemblyName DemoName = new AssemblyName("DynamicClass");
AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(DemoName, AssemblyBuilderAccess.RunAndSave);
//动态创建模块
ModuleBuilder mb = dynamicAssembly.DefineDynamicModule(DemoName.Name, DemoName.Name + ".dll");
//动态创建类
TypeBuilder tb = mb.DefineType(className + Guid.NewGuid().ToString().Replace("-", ""), TypeAttributes.Public);
//动态创建属性
if (lm != null && lm.Count & 0)
foreach (var item in lm)
createProperty(tb, item.Name, item.PropertyType);
//创建动态类型
Type classType = tb.CreateType();
return classT
/// &summary&
/// 动态创建类的属性
/// &/summary&
/// &param name="tb"&承载该属性的类型&/param&
/// &param name="properityName"&属性名,首字母应大写&/param&
/// &param name="properityType"&属性数据类型&/param&
public static FieldBuilder createProperty(TypeBuilder tb, string propertyName, Type propertyType)
//定义属性对应的私有字段
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
//定义属性
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
//定义与属性相关的get方法
MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
propertyType,
Type.EmptyTypes);
ILGenerator getIL = getPropMthdBldr.GetILGenerator();//获取il 生成器
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
getIL.Emit(OpCodes.Ret);
//定义与属性相关的set方法
MethodBuilder setPropMthdBldr = tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null, new Type[] { propertyType });
ILGenerator setIL = setPropMthdBldr.GetILGenerator();
* OpCodes.Ldarg_0:Ldarg是加载方法参数的意思。这里Ldarg_0事实上是对当前对象的引用即this。
* 因为类的实例方法(非静态方法)在调用时,this 是会作为第一个参数传入的。
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldarg_1);//OpCodes.Ldarg_1:加载参数列表的第一个参数了。
setIL.Emit(OpCodes.Stfld, fieldBuilder);//OpCodes.Stfld:用新值替换在对象引用或指针的字段中存储的值。
setIL.Emit(OpCodes.Ret);
//把get/set方法和属性联系起来
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
return fieldB
}View Code
有了以上基础,定义类:SqlQuery,用于组装WHERE条件
using System.Collections.G
using System.L
using System.T
using System.Linq.E
namespace DapperEx
public abstract class SqlQuery
protected int _TopN //查询TOP
protected QueryOrder _O
protected StringBuilder _S //组装的SQL
protected IList&DynamicPropertyModel& _P
//参数动态类
protected string ParamPrefix = "@"; //参数前缀
protected string CustonParamPrefix = "para_"; //参数别名前段
/// &summary&
/// 记录参数名和值
/// &/summary&
protected Dictionary&string, object& ParamValues = new Dictionary&string, object&();
/// &summary&
/// &/summary&
public virtual int TopNum { get { return _TopN } }
/// &summary&
/// &/summary&
public virtual QueryOrder Order { get { return _O } }
/// &summary&
/// SQL字符串,只表示包括Where后面的一段
/// &/summary&
public virtual string Sql
var sb = new StringBuilder();
var arr = Common.UnitMoreSpan(_Sql.ToString()).Split(‘ ‘);
if (arr.Where(m =& !string.IsNullOrEmpty(m)).Count() & 0)
sb.Append("WHERE");
for (int i = 0; i & arr.L i++)
if (i == 0 && (arr[i].ToUpper() == "AND" || arr[i].ToUpper() == "OR"))
if (i & 0 && arr[i - 1] == "(" && (arr[i].ToUpper() == "AND" || arr[i].ToUpper() == "OR"))
sb.Append(" ");
sb.Append(arr[i]);
if (Order != null)
sb.Append(" ");
sb.Append("ORDER BY");
sb.Append(" ");
sb.Append(Order.Field);
sb.Append(" ");
var desc = Order.IsDesc ? "DESC" : "ASC";
sb.Append(desc);
return sb.ToString();
/// &summary&
/// 查询参数对象
/// &/summary&
public object Param
if (this._Param != null && this._Param.Count & 0)
var tyName = "CustomDynamicParamClass";
var modelType = CustomDynamicBuilder.DynamicCreateType(tyName, this._Param);
var model = Activator.CreateInstance(modelType);
foreach (var item in this.ParamValues)
modelType.GetProperty(item.Key).SetValue(model, item.Value, null);
return null;
protected SqlQuery()
this._Sql = new StringBuilder();
/// &summary&
/// &/summary&
/// &param name="top"&&/param&
/// &returns&&/returns&
public SqlQuery Top(int top)
this._TopNum =
return this;
/// &summary&
/// &/summary&
public class SqlQuery&T& : SqlQuery where T : class
private SqlQuery()
/// &summary&
/// &/summary&
/// &returns&&/returns&
public static SqlQuery&T& Builder(DbBase db)
var result = new SqlQuery&T&();
result.ParamPrefix = db.ParamP
/// &summary&
/// 创建排序
/// &/summary&
/// &typeparam name="T"&&/typeparam&
/// &param name="expr"&&/param&
/// &param name="desc"&&/param&
/// &returns&&/returns&
public SqlQuery&T& OrderBy(Expression&Func&T, object&& expr, bool desc)
var field = Common.GetNameByExpress&T&(expr);
this._Order = new QueryOrder() { Field = field, IsDesc = desc };
return this;
/// &summary&
/// &/summary&
/// &param name="top"&&/param&
/// &returns&&/returns&
public SqlQuery&T& Top(int top)
this._TopNum =
return this;
/// &summary&
/// 左括号(
/// &/summary&
/// &param name="isAnd"&true为AND false为OR&/param&
/// &returns&&/returns&
public SqlQuery&T& LeftInclude(bool isAnd = true)
var cn = isAnd ? "AND" : "OR";
this._Sql.Append(" ");
this._Sql.Append(cn);
this._Sql.Append(" ");
this._Sql.Append("(");
return this;
/// &summary&
/// 右括号)
/// &/summary&
/// &returns&&/returns&
public SqlQuery&T& RightInclude()
this._Sql.Append(" ");
this._Sql.Append(")");
return this;
/// &summary&
/// AND方式连接一条查询条件
/// &/summary&
/// &param name="expr"&&/param&
/// &param name="operation"&&/param&
/// &param name="value"&&/param&
/// &returns&&/returns&
public SqlQuery&T& AndWhere(Expression&Func&T, object&& expr, OperationMethod operation, object value)
return Where(expr, operation, value, true);
/// &summary&
Or方式连接一条查询条件
/// &/summary&
/// &param name="expr"&&/param&
/// &param name="operation"&&/param&
/// &param name="value"&&/param&
/// &returns&&/returns&
public SqlQuery&T& OrWhere(Expression&Func&T, object&& expr, OperationMethod operation, object value)
return Where(expr, operation, value, false);
/// &summary&
/// &/summary&
/// &param name="expr"&&/param&
/// &param name="operation"&&/param&
/// &param name="value"&&/param&
/// &param name="isAnd"&true为AND false为OR&/param&
/// &returns&&/returns&
private SqlQuery&T& Where(Expression&Func&T, object&& expr, OperationMethod operation, object value, bool isAnd)
var cn = isAnd ? "AND" : "OR";
var field = Common.GetNameByExpress&T&(expr);
var op = GetOpStr(operation);
StringBuilder sb = new StringBuilder();
this._Sql.Append(" ");
this._Sql.Append(cn);
this._Sql.Append(" ");
this._Sql.Append(field);
this._Sql.Append(" ");
this._Sql.Append(op);
this._Sql.Append(" ");
var model = AddParam(operation, value);
this._Sql.Append(this.ParamPrefix + model.Name);
return this;
/// &summary&
/// 比较符
/// &/summary&
/// &param name="method"&&/param&
/// &returns&&/returns&
private string GetOpStr(OperationMethod method)
switch (method)
case OperationMethod.Contains:
return "LIKE";
case OperationMethod.EndsWith:
return "LIKE";
case OperationMethod.Equal:
return "=";
case OperationMethod.Greater:
return "&";
case OperationMethod.GreaterOrEqual:
return "&=";
case OperationMethod.In:
return "IN";
case OperationMethod.Less:
return "&";
case OperationMethod.LessOrEqual:
return "&=";
case OperationMethod.NotEqual:
return "&&";
case OperationMethod.StartsWith:
return "LIKE";
return "=";
/// &summary&
/// 创建参数
/// &/summary&
/// &param name="operation"&&/param&
/// &param name="value"&&/param&
/// &returns&&/returns&
private object CreateParam(OperationMethod method, object value)
switch (method)
case OperationMethod.Contains:
return string.Format("%{0}%", value);
case OperationMethod.EndsWith:
return string.Format("%{0}", value);
case OperationMethod.Equal:
case OperationMethod.Greater:
case OperationMethod.GreaterOrEqual:
case OperationMethod.In:
case OperationMethod.Less:
case OperationMethod.LessOrEqual:
case OperationMethod.NotEqual:
case OperationMethod.StartsWith:
return string.Format("{0}%", value);
/// &summary&
/// 通过方法和值创建一个参数对象并记录
/// &/summary&
/// &param name="method"&&/param&
/// &param name="value"&&/param&
/// &returns&&/returns&
private DynamicPropertyModel AddParam(OperationMethod method, object value)
if (this._Param == null)
this._Param = new List&DynamicPropertyModel&();
var i = (this._Param.Count + 1).ToString();
var model = new DynamicPropertyModel();
model.Name = CustonParamPrefix +
model.PropertyType = value.GetType();
this._Param.Add(model);
switch (method)
case OperationMethod.Contains:
this.ParamValues.Add(model.Name, string.Format("%{0}%", value));
case OperationMethod.EndsWith:
this.ParamValues.Add(model.Name, string.Format("%{0}", value));
case OperationMethod.Equal:
this.ParamValues.Add(model.Name, value);
case OperationMethod.Greater:
this.ParamValues.Add(model.Name, value);
case OperationMethod.GreaterOrEqual:
this.ParamValues.Add(model.Name, value);
case OperationMethod.In:
this.ParamValues.Add(model.Name, value);
case OperationMethod.Less:
this.ParamValues.Add(model.Name, value);
case OperationMethod.LessOrEqual:
this.ParamValues.Add(model.Name, value);
case OperationMethod.NotEqual:
this.ParamValues.Add(model.Name, value);
case OperationMethod.StartsWith:
this.ParamValues.Add(model.Name, string.Format("{0}%", value));
}View Code
&基础工作完成后,接下来就写扩展方法:
/// &summary&
/// &/summary&
/// &typeparam name="T"&&/typeparam&
/// &param name="dbs"&&/param&
/// &param name="sql"&&/param&
/// &returns&&/returns&
public static IList&T& Query&T&(this DbBase dbs, SqlQuery sql = null) where T : class
var db = dbs.DbC
var result = new List&T&();
var sqlStr = CreateQuerySql&T&(dbs, sql);
if (sql == null || sql.Param == null)
result = db.Query&T&(sqlStr).ToList();
result = db.Query&T&(sqlStr, sql.Param).ToList();
/// &summary&
/// 创建查询语句
/// &/summary&
/// &typeparam name="T"&&/typeparam&
/// &param name="dbs"&&/param&
/// &param name="sql"&&/param&
/// &returns&&/returns&
private static string CreateQuerySql&T&(DbBase dbs, SqlQuery sql) where T : class
var sqlStr = "";
var tbName = Common.GetTableName&T&();
if (sql == null)
sqlStr = string.Format("SELECT * FROM {0}", tbName);
var topStr = "*";
if (sql.TopNum & 0)
if (dbs.DbType == DBType.SqlServer || dbs.DbType == DBType.SqlServerCE)
sqlStr = string.Format("SELECT TOP {0} {1} FROM {2} {3}", sql.TopNum, "*", tbName, sql.Sql);
else if (dbs.DbType == DBType.Oracle)
var wStr = sql.S
if (wStr.ToUpper().Contains("WHERE"))
if (wStr.ToUpper().Contains("ORDER BY"))
wStr = wStr.Insert(wStr.ToUpper().LastIndexOf("ORDER BY"), string.Format(" AND
ROWNUM &= {0} ", sql.TopNum));
wStr = wStr + string.Format(" AND
ROWNUM &= {0} ", sql.TopNum);
if (wStr.ToUpper().Contains("ORDER BY"))
wStr = wStr.Insert(wStr.ToUpper().LastIndexOf("ORDER BY"), string.Format(" WHERE
ROWNUM &= {0} ", sql.TopNum));
wStr = wStr + string.Format(" WHERE
ROWNUM &= {0} ", sql.TopNum);
sqlStr = string.Format("SELECT {0} FROM {1} {2}", "*", tbName, wStr);
sqlStr = string.Format("SELECT {0} FROM {1} {2} LIMIT {3}", "*", tbName, sql.Sql, sql.TopNum);
sqlStr = string.Format("SELECT {0} FROM {1} {2}", "*", tbName, sql.Sql);
return sqlS
}View Code
最后是测试方法:
[TestMethod]
public void QueryNoWhere()//无条件的查询,相当于GetAll
using (var db = CreateDbBase())
var result = db.Query&Account&();
Console.WriteLine("查询出数据条数:" + result.Count);
[TestMethod]
public void Query()//条件查询
using (var db = CreateDbBase())
var d = SqlQuery&Account&.Builder(db).AndWhere(m =& m.Age, OperationMethod.Less, 20)
.LeftInclude()//此表示左括号,所以后面必须有右括号与之对应
.AndWhere(m =& m.CreateTime, OperationMethod.Greater, DateTime.Now.AddDays(-5))
.OrWhere(m =& m.Name, OperationMethod.Contains, "张")
.RightInclude()//右括号
.Top(10)//前10条
.AndWhere(m =& m.Age, OperationMethod.In, new List&int&() { 15 })
.OrderBy(m =& m.Age, true);
//WHERE Age & @para_1 AND ( CreateTime & @para_2 OR Name LIKE @para_3 ) AND Age IN @para_4 ORDER BY Age DESC
var result = db.Query&Account&(d);
Console.WriteLine("查询出数据条数:" + result.Count);
&OK,今天的扩展到此结束,后续系列将会对修改、批量修改、删除、批量删除、分页进行扩展希望大家多多关注,觉得对自己有所帮助或有意见的,欢迎留言,觉得不错的,不要吝啬你的鼠标,点点支持,点点推荐,谢谢啦!!!
再次申明:暂时先放下代码和性能问题,在全部扩展完成之后,我会进行一次尽可能的代码重构和一些性能优化
本次扩展源码:/s/1o6z33M6
技术交流学习或者有任何问题欢迎加群 : &public class Dog
public int? Age { }
public Guid Id { }
public string Name { }
public float? Weight { }
public int Ignoredoperty { get { return 1; } }
var guid = Guid.NewGuid();
var dog = connection.Query&Dog&(&select Age = @Age, Id = @Id&, new { Age = (int?)null, Id = guid });
dog.Count()
.IsEqualTo(1);
dog.First().Age
.IsNull();
dog.First().Id
.IsEqualTo(guid);
执行一个查询,并把结果映射到一个动态 object 的 list
public static IEnumerable&dynamic& Query (this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null, bool buffered = true)
该方法将执行 SQL,并返回一个动态 list,即 var 变量。
var rows = connection.Query(&select 1 A, 2 B union all select 3, 4&);
((int)rows[0].A)
.IsEqualTo(1);
((int)rows[0].B)
.IsEqualTo(2);
((int)rows[1].A)
.IsEqualTo(3);
((int)rows[1].B)
.IsEqualTo(4);
rows[0] 这种访问方式会出错,不知道示例是怎么给的~
执行一个不返回结果的 Command
public static int Execute(this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null)
connection.Execute(@&
set nocount on
create table #t(i int)
set nocount off
select @a a union all select @b
set nocount on
drop table #t&, new {a=1, b=2 })
.IsEqualTo(2);
多次执行一个 Command
相同的签名也可以让你方便高效地对一个命令执行多次,例如批量加载数据(bulk-load data)。
connection.Execute(@&insert MyTable(colA, colB) values (@a, @b)&,
new[] { new { a=1, b=1 }, new { a=2, b=2 }, new { a=3, b=3 } }
).IsEqualTo(3); // 3 rows inserted: &1,1&, &2,2& and &3,3&
对任何类型实现 T 为 IEnumerable 的参数都可以执行。
Dapper 的主要特点是性能。以下数据显示对一个数据库执行 SELECT 出 500 条,并把数据映射到对象中需要多长时间。
性能测试分为三个方面:
POCO 序列化框架,支持从数据库获得静态类型的对象。使用原始的 SQL。
动态序列化框架,支持返回对象的动态列表。
典型的框架用法。往往不会涉及编写 SQL。
Performance of SELECT mapping over 500 iterations - POCO 序列化
持续时间(毫秒)
Hand coded (using a SqlDataReader)
Can be faster
Dapper ExecuteMapperQuery
ServiceStack.OrmLite (QueryById)
PetaPoco 
SubSonic CodingHorror
NHibernate SQL
Linq 2 SQL ExecuteQuery
Entity framework ExecuteStoreQuery
Performance of SELECT mapping over 500 iterations - dynamic 序列化
持续时间(毫秒)
Dapper ExecuteMapperQuery (dynamic)
Simple.Data
Performance of SELECT mapping over 500 iterations - 典型用法
持续时间(毫秒)
Linq 2 SQL CompiledQuery
Not super typical involves complex code
NHibernate HQL
Linq 2 SQL
Entity framework
SubSonic ActiveRecord.SingleOrDefault
参数化的查询
参数可以作为匿名类来传递。这使你可以轻松地给命名参数,只要简单地剪切和粘贴 SQL 片断,并在查询分析器中执行即可。
new {A = 1, B = &b&} // A will be mapped to the param @A, B to the param @B
Dapper 运行让你传递 IEnumerable,自动地参数化的查询。
例如下面 SQL 的 in 查询:
connection.Query&int&(&select * from (select 1 as Id union all select 2 union all select 3) as X where Id in @Ids&, new { Ids = new int[] { 1, 2, 3 });
select * from (select 1 as Id union all select 2 union all select 3) as X where Id in (@Ids1, @Ids2, @Ids3)& // @Ids1 = 1 , @Ids2 = 2 , @Ids2 = 3
缓存和非缓存的 readers
Dapper 的默认动作是执行 SQL 并在返回时缓冲整个 reader。在大多数情况下,这是理想的,因为它能最大限度地减少数据库中的共享锁,以及减少数据库的网络时间。
但是,在执行庞大查询时,你可能为了减少内存的占用,只加载需要的对象。要做到这点,通过缓冲到查询方法中。
/// &summary&
/// NonBuffered
/// 将会抛出异常,Invalid attempt to Read when reader is closed.
/// &/summary&
public static void TestBasicStringUsageAsyncNonBuffered()
var query = DbHelp.QueryAsync&string&(new CommandDefinition(&select 'abc' as Value union all select @txt&, new { txt = &def& }, flags: CommandFlags.None));
var arr = query.Result.ToArray();
arr.IsSequenceEqualTo(new[] { &abc&, &def& });
/// &summary&
/// Buffered
/// 不会抛出异常
/// &/summary&
public static void TestBasicStringUsageAsyncBuffered()
var query = DbHelp.QueryAsync&string&(new CommandDefinition(&select 'abc' as Value union all select @txt&, new { txt = &def& }, flags: CommandFlags.Buffered));
var arr = query.Result.ToArray();
arr.IsSequenceEqualTo(new[] { &abc&, &def& });
/// &summary&
/// Pelined
/// 将会抛出异常,Invalid attempt to Read when reader is closed.
/// &/summary&
public static void TestBasicStringUsageAsyncPipelined()
var query = DbHelp.QueryAsync&string&(new CommandDefinition(&select 'abc' as Value union all select @txt&, new { txt = &def& }, flags: CommandFlags.Pipelined));
var arr = query.Result.ToArray();
arr.IsSequenceEqualTo(new[] { &abc&, &def& });
Dapper 允许你把单行映射到多个对象。如果你想避免额外的查询和加载关联,那么这个功能就很关键了。
@&select * from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id&;
var data = connection.Query&Post, User, Post&(sql, (post, user) =& { post.Owner = return});
var post = data.First();
post.Content.IsEqualTo(&Sams Post1&);
post.Id.IsEqualTo(1);
post.Owner.Name.IsEqualTo(&Sam&);
post.Owner.Id.IsEqualTo(99);
提示:Dapper 假定你的 ID 列被命名为“ID”或“id”,如果你的主键是不同的,或者你想在点上拆分宽行点,而不是“ID”,可以使用可选的'splitOn'参数。
Dapper 允许你在一次查询中处理多个结果的集合。
select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id&;
using (var multi = connection.QueryMultiple(sql, new {id=selectedId}))
var customer = multi.Read&Customer&().Single();
var orders = multi.Read&Order&().ToList();
var returns = multi.Read&Return&().ToList();
Dapper 完全支持存储过程:
var user = cnn.Query&User&(&spGetUser&, new {Id = 1},
commandType: CommandType.StoredProcedure).First();}}}
如果你想要更灵活的操作,可以这样做:
var p = new DynamicParameters();
p.Add(&@a&, 11);
p.Add(&@b&, dbType: DbType.Int32, direction: ParameterDirection.Output);
p.Add(&@c&, dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);
cnn.Execute(&spMagicProc&, p, commandType: CommandType.StoredProcedure);
int b = p.Get&int&(&@b&);
int c = p.Get&int&(&@c&);
Ansi Strings 和 varchar
Dapper 支持 varchar 参数,如果你在一个 varchar 列上执行一个 where 语句,确保下面方式传递参数:
Query&Thing&(&select * from Thing where Name = @Name&, new {Name = new DbString { Value = &abcde&, IsFixedLength = true, Length = 10, IsAnsi = true });
在 SQL Server 上,当查询非 Unicode 时,查询 Unicode 和 ANSI 时需要使用 Unicode。
限制和注意事项
对于 Dapper 执行的每个查询的缓存信息,使得它能够快速地物化对象和处理参数。当前的实现把信息缓存在一个 ConcurrentDictionary 对象中。它存储的对象永远不会被刷新。如果你生成的 SQL 字符串没有使用参数,那么可能会出现命中内存问题。我们把字典转换成 LRU(Least Recently Used)缓存。
ORM 的很多特点都被 Dapper 去掉了,没有身份地图(Identity Map),没有更新/选择的助手等。
Dapper 不会管理你连接的生命周期,它假定它得到的连接是打开的,并且不存在 DataReader 枚举(除非启用 MARS)。
什么是 Mars?它是在创建数据库连接时指定的,下面是 Dapper 中连接 SQL Server 的示例:
public static SqlConnection GetOpenConnection(bool mars = false)
var cs = connectionS
SqlConnectionStringBuilder scsb = new SqlConnectionStringBuilder(cs);
scsb.MultipleActiveResultSets = true;
cs = scsb.ConnectionS
var connection = new SqlConnection(cs);
connection.Open();
如果指定了 Mars,那么还会创建 SqlConnectionStringBuilder,并指定其 MultipleActiveResultSets 属性为 true。不过,看 Dapper 的例子,貌似 SQL Server 是有 Mars 的,但 MySQL 没有。
Dapper 能运行在我的 db 提供者上吗?
Dapper 能运行在所有 .net ado 提供者上,包括 sqlite,sqlce,firebird,,MySQL,PostgreSQL 和 SQL Server。
有例子的完整例子列表吗?
Dapper 在测试项目中有完整的测试套件。
谁在使用 Dapper?
目前使用 Dapper 的有 Stack Overflow 和 helpdesk。
(if you would like to be listed here let me know)
github Dapper
stackoverflow Dapper
A Look at Dapper.NET
优质网站模板}

我要回帖

更多关于 dapper 动态参数 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信