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

发布于 2024-11-17 14:16:35 字数 1118 浏览 2 评论 0原文

我在工作中结合使用 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();

cgedAnimal 包含公共属性 AnimalId 和 AnimalType 以及 getter 和 setter。

但是,在执行此代码时,我收到以下错误:

类型: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 的回复进行了第二次编辑。

I'm using a combination of LINQ and Dapper in my work. I'm replacing my LINQ code with Dapper in places for performance reasons. I have a lot of LINQ data objects created by dragging and dropping into the Visual Studio database diagram from SQL Server.

In the following instance I already have a LINQ object in memory and I'd like to pass it to Dapper as the parameters for a query. For example:

Animal animal = con.Query<Animal>(" select * " +
        " from animal " +
        " where animalid = @AnimalId " +
        " and animaltype = @AnimalType ",
        cagedAnimal).SingleOrDefault();

cagedAnimal contains a public properties AnimalId and AnimalType with getters and setters.

However on executing this code I get the following error:

The type : SMDApp.Models.Animal is
not supported by dapper

The following code does work:

Animal animal = con.Query<Animal>(" select * " +
            " from animal " +
            " where animalid = @AnimalId " +
            " and animaltype = @AnimalType ",
            new 
            { 
            AnimalId = cagedAnimal.AnimalId, 
            AnimalType = cagedAnimal.AnimalType 
            }
            ).SingleOrDefault();

It'd be more convenient for me to use an existing object particularly where I'm using more than one property of the object as a parameter for the query. Can anybody tell my why this works for an anonymous object but not an auto generated LINQ object?

Edited in response to Ben Robinson's reply.

Edited a second time in response to Marc Gravell's reply.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

聆听风音 2024-11-24 14:16:35

简短的版本应该已经可以工作了;基于错误:

类型:dapper 不支持 SMDApp.Models.CgedAnimal

我的结论是您实际上传递的是 new {cgedAnimal} 而不是 cgedAnimal,你的 CgedAnimal 有一个属性(Parent,也许?),它本身就是一个 CgedAnimal,而哪个 dapper 不能 理解。当前的行为是为所提供的参数对象的每个公共属性添加一个参数 - 如果它无法弄清楚如何将任何属性发送到数据库,它抱怨道。您应该发现仅包含值成员的简单 POCO 可以正常工作。

然而!请注意,它不会尝试解析您的 SQL - 特别是,它不会检查所提供的查询中的参数。因此,使用 POCO 方法意味着您要向查询添加不必要的属性。

我们广泛使用 dapper,我们只是使用以下方法:

 new { obj.Foo, obj.Bar, id, key = "something else" }

The short version is that should already work; based on the error:

The type : SMDApp.Models.CagedAnimal is not supported by dapper

I conclude that either you are actually passing new {cagedAnimal} instead of cagedAnimal, or, your CagedAnimal has a property (Parent, perhaps?) that is itself a CagedAnimal, and which dapper can't understand. The current behaviour is that a parameter is added for every public property of the provided parameter object - and if it can't figure out how to send any of the properties to the database, it complains. You should find that a simple POCO with just value members works fine.

However! Note that it does not ever attempt to parse your SQL - in particular, it does not check for parameters in the query provided. As such, using the POCO approach will mean that you are adding unnecessary properties to the query.

We use dapper extensively, and we just use the approach:

 new { obj.Foo, obj.Bar, id, key = "something else" }
携余温的黄昏 2024-11-24 14:16:35

Marc 刚刚对 修复此问题,特别是:

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

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

--

Dapper 用于不执行底层 SQL 语句的解析,因此例如:

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

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

它变得复杂,因为要 100% 正确,您需要处理边缘情况 EG:@AnimalId 进入字符串 select '@AnimalId' -- @AnimalId \* @AnimalId *\?正则表达式确实有点棘手,我还没有考虑到每一个边缘情况。例如:Oracle 在其参数前面加上 : 前缀,这使事情变得更加复杂。

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

Marc just committed a change to fix for this issue in particular:

  1. We perform a trivial validation before sending attempting to translate properties to params. For example Dapper will not not send any params to the server for this case: cnn.Query("select 1", new {bla = 1}) cause "bla" does not exist in the string. This validation is skipped for stored procs.

  2. The error, which was rather cryptic, is now fixed and much improved.

--

Dapper used to perform no parsing of the underlying SQL statement, so for example:

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

Contains a single param called @AnimalId.

It gets complicated cause, to be 100% correct you need to handle edge cases EG: @AnimalId into the string select '@AnimalId' -- @AnimalId \* @AnimalId *\? The regex does get a bit tricky, I have not thought through every edge case. For example: Oracle prefixes its params with a : which complicates things more.

Since dapper knew nothing about the params in the string, it decided to send in every public property as a parameter. Some of your public properties can not be mapped to DbParameters so it complained.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文