带有参数列表的Dapper查询

我试图用Dapper运行一个带有一组已知参数的查询,但是带有这些参数的值列表。 我想要做的一个简单例子是:

DateTime endDate = DateTime.Now; DateTime startDate = endDate.AddHours(-24); string query = "select COUNT(*) from Test where Status = @Status AND DateCreated  new { Status = 1, Hour = hour, })); 

Dapper抛出一个exception’参数’@Status’必须定义’。 我知道Dapper在进行批量插入和更新时可以处理参数列表,但是它不能用于选择吗?

啊,我想我明白你的意思了……

是的,有一个我们支持Execute的场景,不支持Query,具体来说:使用一系列不同的参数值顺序运行相同的操作。 这对于Execute是有意义的,但对于查询,它可能意味着您应该使用in查看不同的查询。 或者,只需循环和连接。

相反,它正在查看单个参数对象并查找公共值 – 可枚举的dapper没有任何合适的参数值。

试试这个:

 List names = new List { "Bob", "Fred", "Jack" }; string query = "select * from people where Name in @names"; var stuff = connection.Query(query, new {names}); 

我知道我迟到了这个派对,但我想我理解这个请求意味着你只想传递一些属性并根据这些动态属性生成你的查询。

使用下面的代码,我可以使用任何类型,然后填充并传入该类型的对象,并设置一些值(我称之为我的查询对象),并生成查询以查找与值匹配的对象您在查询对象中设置。

*小心bools和具有默认值的东西。

动态查询示例

  public IEnumerable Query(T templateobject) { var sql = "SELECT * From " + typeof(T).Name + " Where "; var list = templateobject.GetType().GetProperties() .Where(p => p.GetValue(templateobject) != null) .ToList(); int i = 0; Dictionary dbArgs = new Dictionary(); list.ForEach(x => { sql += x.Name + " = @" + x.Name; dbArgs.Add(x.Name, x.GetValue(templateobject)); if (list.Count > 1 && i < list.Count - 1) { sql += " AND "; i++; } }); Debug.WriteLine(sql); return _con.Query(sql, dbArgs).ToList(); } 

用法

* repo是包含上述function的类

 var blah = repo.Query(new Domain() { Id = 1, IsActive=true }); 

产量

 SELECT * From Domain Where Id = @Id AND IsActive = @IsActive 

然后它会吐出与上述查询匹配的任何“域名”。

 DECLARE @Now datetime SET @Now = getdate() SELECT DATEADD( hh, -n, @Now ) AS StartDate, DATEADD( hh, -n+1, @Now ) AS EndDate INTO #DateRanges FROM Numbers WHERE n <= 24 SELECT COUNT(*) AS [Count], #DateRanges.StartDate FROM Test JOIN #DateRanges ON Test.DateCreated >= #DateRanges.StartDate AND Test.DateCreated < #DateRanges.EndDate GROUP BY #DateRanges.StartDate 

我就是这样做的,但这假设了一件事:数据库中有一个名为“Numbers”的表,其中包含任意数量的整数,每行一个,从1开始,其中至少有24个数字。

也就是说,表格如下所示:

 n ----- 1 2 3 4 5 ... 

如果你没有这样的表,那么为这个命令制作一个表非常快速和容易:

 CREATE TABLE #Numbers ( n int ) SET NOCOUNT ON INSERT #Numbers values (1); GO INSERT #Numbers SELECT n + (SELECT COUNT(*) FROM #Numbers) FROM #Numbers GO 16 --execute batch 16 times to create 2^16 integers. 

您不能在存储过程中拥有多个批次,但可以在文本命令中使用。 GO 16运行前一批次16次。 如果您需要在存储过程中使用此function,则可以多次重复第二次INSERT命令,而不是使用批处理。 对于这个特定的查询,2 ^ 16个整数是过度的,但它是我需要时复制和粘贴的命令,2 ^ 16通常就足够了,而且速度太快,以至于我通常都不用费心去改变它。 GO 5将产生32个整数,这足以满足24个日期范围。

这是一个完整的脚本,说明了这个工作:

 --Create a temp table full of integers. This could also be a static --table in your DB. It's very handy. --The table drops let us run this whole script multiple times in SSMS without issue. IF OBJECT_ID( 'tempdb..#Numbers' ) IS NOT NULL DROP TABLE #Numbers CREATE TABLE #Numbers ( n int ) SET NOCOUNT ON INSERT #Numbers values (1); GO INSERT #Numbers SELECT n + (SELECT COUNT(*) FROM #Numbers) FROM #Numbers GO 16 --execute batch 16 times to create 2^16 integers. --Create our Test table. This would be the real table in your DB, -- so this would not go into your SQL command. IF OBJECT_ID( 'tempdb..#Test' ) IS NOT NULL DROP TABLE #Test CREATE TABLE #Test ( [Status] int, DateCreated datetime ) INSERT INTO #Test SELECT 1, DATEADD( hh, -n, getdate() ) FROM #Numbers WHERE n <= 48 --#Test now has 48 records in it with one record per hour for --the last 48 hours. --This drop would not be needed in your actual command, but I --add it here to make testing this script easier in SSMS. IF OBJECT_ID( 'tempdb..#DateRanges' ) IS NOT NULL DROP TABLE #DateRanges --Everything that follows is what would be in your SQL you send through Dapper --if you used a static Numbers table, or you might also want to include --the creation of the #Numbers temp table. DECLARE @Now datetime SET @Now = getdate() SELECT DATEADD( hh, -n, @Now ) AS StartDate, DATEADD( hh, -n+1, @Now ) AS EndDate INTO #DateRanges FROM #Numbers WHERE n <= 24 /* #DateRanges now contains 24 rows that look like this: StartDate EndDate 2016-08-04 15:22:26.223 2016-08-04 16:22:26.223 2016-08-04 14:22:26.223 2016-08-04 15:22:26.223 2016-08-04 13:22:26.223 2016-08-04 14:22:26.223 2016-08-04 12:22:26.223 2016-08-04 13:22:26.223 ... Script was run at 2016-08-04 16:22:26.223. The first row's end date is that time. This table expresses 24 one-hour datetime ranges ending at the current time. It's also easy to make 24 one-hour ranges for one calendar day, or anything similar. */ --Now we just join that table to our #Test table to group the rows those date ranges. SELECT COUNT(*) AS [Count], #DateRanges.StartDate FROM #Test JOIN #DateRanges ON #Test.DateCreated >= #DateRanges.StartDate AND #Test.DateCreated < #DateRanges.EndDate GROUP BY #DateRanges.StartDate /* Since we used two different getdate() calls to populate our two tables, the last record of our #Test table is outside of the range of our #DateRange's last row by a few milliseconds, so we only get 23 results from this query. This script is just an illustration. */