我在工作中使用LINQ和Dapper的组合。出于性能原因,我正在用Dapper替换我的LINQ代码。我通过从SQL Server拖放到Visual Studio数据库图表中创建了很多LINQ数据对象。
在下面的例子中,我已经在内存中有一个LINQ对象,我想将它作为查询的参数传递给Dapper。例如:
Animal animal = con.Query<Animal>(" select * " +
" from animal " +
" where animalid = @AnimalId " +
" and animaltype = @AnimalType ",
cagedAnimal).SingleOrDefault();
cagedAnimal包含一个带有getter和setter的公共属性AnimalId和AnimalType。
但是在执行此代码时,我收到以下错误:
类型:SMDApp.Models.Animal是 dapper不支持
以下代码可行:
Animal animal = con.Query<Animal>(" select * " +
" from animal " +
" where animalid = @AnimalId " +
" and animaltype = @AnimalType ",
new
{
AnimalId = cagedAnimal.AnimalId,
AnimalType = cagedAnimal.AnimalType
}
).SingleOrDefault();
使用现有对象会更方便,特别是在我使用对象的多个属性作为查询参数的情况下。任何人都可以告诉我为什么这适用于匿名对象而不是自动生成的LINQ对象?
编辑回应本·罗宾逊的回复。
第二次编辑回应Marc Gravell的回复。
答案 0 :(得分:4)
短版本应该已经可以使用;根据错误:
类型:dapper不支持SMDApp.Models.CagedAnimal
我的结论是,您实际上要传递new {cagedAnimal}
而不是cagedAnimal
,或,您的CagedAnimal
有一个属性(Parent
,也许?)本身就是CagedAnimal
,而且这个小巧玲珑无法理解。当前的行为是为所提供的参数对象的每个公共属性 添加一个参数 - 如果它无法弄清楚如何将任何属性发送到数据库,它抱怨。您应该会发现只有值成员的简单POCO可以正常工作。
然而!请注意,它不会尝试解析您的SQL - 特别是,它不会检查提供的查询中的参数。因此,使用POCO方法意味着您要向查询添加不必要的属性。
我们广泛使用短小精悍,我们只是使用这种方法:
new { obj.Foo, obj.Bar, id, key = "something else" }
答案 1 :(得分:3)
Marc特别对fix for this issue进行了更改:
在发送尝试将属性转换为params之前,我们执行了一个简单的验证。例如,在这种情况下,Dapper不会向服务器发送任何参数:cnn.Query(“select 1”,new {bla = 1})因为字符串中不存在“bla”。对于存储过程,将跳过此验证。
这个相当神秘的错误现在已得到修复并大大改善。
-
Dapper过去不执行底层SQL语句的解析,例如:
@"select *
from animal
where animalid = @AnimalId"
包含一个名为@AnimalId
的参数。
这是一个复杂的原因,为了100%正确你需要处理边缘情况EG:@AnimalId
到字符串select '@AnimalId' -- @AnimalId \* @AnimalId *\
?正则表达式确实有点棘手,我没有想过每个边缘情况。例如:Oracle使用:
为其参数添加前缀,这会使事情复杂化。
由于dapper对字符串中的params一无所知,因此决定将每个公共属性作为参数发送。您的某些公共属性无法映射到DbParameters
,因此抱怨。