c#代码中的动态SQL查询?

时间:2017-09-28 21:43:19

标签: c# cqrs

我在我的项目中使用Dapper。通常情况下,我需要根据某些变量更改SQL查询。

例如:

public override QueryResult Handle(Query query) 
{
    var sql = "SELECT field FROM table";

    if(someModel.IncludeSomething){
        // add inner join something + add SELECT something.field
    }

    if(conditionN){...}

    return Connection.Query<QueryResult>(sql, query);
}

如何在项目中使用动态SQL查询?

3 个答案:

答案 0 :(得分:2)

我有同样的情况,用动态过滤器开发自定义仪表板/报告,分组,有时需要加入其他表格。

由于存储过程方法在这种情况下不能很好地发挥作用,因此我开发了自己的库SqlKata,这是一个动态查询构建器,提供上述要求,而不会牺牲安全性和性能,因为它使用参数绑定技术。检查出来,希望你会发现它有用:)

答案 1 :(得分:1)

我尽力而不是来动态构建SQL查询。我已经多次参加过这样做的项目,这一直是麻烦的源头。与存储过程相比,动态构造的SQL将更频繁地引起查询解析和规划成本,总是会导致更高的数据传输成本,并且更可能导致无法预料,笨拙,无法执行且有问题的查询。基本上,这种方法保证不会扩展。

相反,如果可能的话,维护一组共同覆盖查询空间的调优存储过程。在某些情况下,适用的存储过程将比您需要的更通用(例如,如果您知道查询永远不会发生,那么您可以完全不使用“WHERE [Foo] = @foo OR @foo IS NULL”子句在Foo上匹配)。接受该成本或为更通用的存储过程成为瓶颈的情况编写专门的存储过程。

如果你忽略我的建议并动态构造SQL,那么至少在任何地方使用参数而不是值。如果为一个查询构造“WHERE [Foo] = 1”而对另一个查询构造“WHERE [Foo] = 2”,则两个查询将单独编译。相反,你为两者构造“WHERE [Foo] = @foo”并为第一个传递@foo = 1而第二个传递@foo = 2,那么你至少只会产生一次编译成本,并且缓存的查询计划将用于第二次通话。

答案 2 :(得分:1)

不考虑性能问题(可能会也可能不会),我会使用几种方法,具体取决于最简单但可维护的方法。

  1. 更好地创建适合DSL(特定于域的语言)的视图/存储过程。这应该减少动态SQL的需要
  2. 如果选项1不可行,那么您可以使用ORM(不适合高性能或可维护的复杂查询)或具有类型支持的数据映射器来构建此类查询。我使用自己的SqlFu,它具有强类型查询构建器,允许条件,只要您查询一个表/视图/存储过程
  3. 通常是1和2的组合。
  4. 如果您需要动态创建涉及联接的查询,可能会提示设计不当和强烈的维护气味。我会说再想一想,找到一种方法来重构它。

    就个人而言,我没有遇到选项1-2无法解决的问题,但也许您的报告要求比我的复杂得多。