使用LINQ自动生成类型的Dapper参数化查询

时间:2011-06-29 11:46:23

标签: c# linq dapper

我在工作中使用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的回复。

2 个答案:

答案 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进行了更改:

  1. 在发送尝试将属性转换为params之前,我们执行了一个简单的验证。例如,在这种情况下,Dapper不会向服务器发送任何参数:cnn.Query(“select 1”,new {bla = 1})因为字符串中不存在“bla”。对于存储过程,将跳过此验证。

  2. 这个相当神秘的错误现在已得到修复并大大改善。

  3. -

    Dapper过去不执行底层SQL语句的解析,例如:

    @"select * 
    from animal
    where animalid = @AnimalId"
    

    包含一个名为@AnimalId的参数。

    这是一个复杂的原因,为了100%正确你需要处理边缘情况EG:@AnimalId到字符串select '@AnimalId' -- @AnimalId \* @AnimalId *\?正则表达式确实有点棘手,我没有想过每个边缘情况。例如:Oracle使用:为其参数添加前缀,这会使事情复杂化。

    由于dapper对字符串中的params一无所知,因此决定将每个公共属性作为参数发送。您的某些公共属性无法映射到DbParameters,因此抱怨。