在C#/。NET3.5中构造动态SQL查询的最佳方法?

时间:2020-03-05 18:53:30  来源:igfitidea点击:

我目前正在从事的项目涉及重构CCom对象,该对象用作对某些Sql 2005数据库的数据库访问层。

现有代码的作者已使用字符串和许多if语句手动构建了所有sql查询,以构造相当复杂的sql语句(〜10个联接,> 10个子选择,〜15-25个条件和GroupBy语句)。基表总是相同的,但是联接,条件和分组的结构取决于传递到我的类/方法中的一组参数。

像这样构造sql查询确实可以,但是它显然不是一个非常优雅的解决方案(而且也很难阅读/理解和维护)...我自己可以编写一个简单的" querybuilder",但是我很确定我不是第一个遇到这种问题的人,因此我的问题是:

  • 我们如何构造数据库查询?
  • C#是否提供一种简单的方法来动态构建查询?

解决方案

回答

LINQ是必经之路。

回答

我们可能需要考虑使用LINQ或者类似这样的O / R映射器:http://www.llblgen.com/

回答

我使用Cand Linq进行了类似的操作,以根据用户输入过滤日志条目(请参阅条件Linq查询):

IQueryable<Log> matches = m_Locator.Logs;

// Users filter
if (usersFilter)
    matches = matches.Where(l => l.UserName == comboBoxUsers.Text);

 // Severity filter
 if (severityFilter)
     matches = matches.Where(l => l.Severity == comboBoxSeverity.Text);

 Logs = (from log in matches
         orderby log.EventTime descending
         select log).ToList();

编辑:直到最后一条语句中的.ToList()才执行查询。

回答

这就是我要做的方式:

public IQueryable<ClientEntity> GetClients(Expression<Func<ClientModel, bool>> criteria)
    {
        return (
            from model in Context.Client.AsExpandable()
            where criteria.Invoke(model)
            select new Ibfx.AppServer.Imsdb.Entities.Client.ClientEntity()
            {
                Id = model.Id,
                ClientNumber = model.ClientNumber,
                NameFirst = model.NameFirst,
                //more propertie here

            }
        );
    }

我们传入的Expression参数将是将使用不同的WHERE子句,JOINS等构建的动态查询。此Expression将在运行时被调用并提供我们所需的信息。

以下是如何调用它的示例:

public IQueryable<ClientEntity> GetClientsWithWebAccountId(int webAccountId)
    {
        var criteria = PredicateBuilder.True<ClientModel>();
        criteria = criteria.And(c => c.ClientWebAccount.WebAccountId.Equals(webAccountId));
        return GetClients(criteria);
    }

回答

值得考虑的是,是否可以将其实现为参数化的支持过程并在数据库中对其进行优化,而不是在运行时通过LINQ或者ORM动态生成SQL。通常,这会更好地执行。我知道它有点过时,但有时是最有效的方法。

回答

如果使用Cand .NET 3.5,加上MS SQL Server,则LINQ to SQL绝对是必经之路。如果我们使用的不是该组合,则建议我们使用ORM路由,例如nHibernate或者Subsonic。

回答

除非执行时间真的很重要,否则我将考虑重构业务逻辑,这种业务逻辑(经常)倾向于找到数据层并存储到数百万亿个存储过程。在可维护性,可编辑性和添加性方面,我一直试图(作为我的C程序员)将代码提升到业务层。

尝试整理别人的8000行SQL脚本不是我最喜欢的任务。

:)

// W

回答

我了解Linq的潜力,但我还没有看到有人尝试对Ben所建议的复杂性进行Linq查询

the fairly complex sql statement (~10 joins, >10 sub selects, ~15-25 where conditions and GroupBy's)

是否有人提供大型Linq查询的示例,以及有关其可管理性的任何评论?

回答

Linq to SQL与System.Linq.Dynamic一起带来了一些不错的可能性。

我在这里发布了一些示例代码片段:
http://blog.huagati.com/res/index.php/2008/06/23/application-architecture-part-2-data-access-layer-dynamic-linq

...和这里:
http://episteme.arstechnica.com/eve/forums/a/tpc/f/6330927813/m/717004553931?r=777003863931#777003863931

回答

我来晚了,没有机会投票,但是有一个很好的解决方案我从未考虑过:将过程/函数与linq-to-object结合使用。我想是to-xml或者to-datatable。

在这种情况下,我一直处于这种状态,它具有巨大的动态构建的查询,虽然取得了令人印象深刻的成就,但其复杂性却导致了一场噩梦。我有很多绿色评论来帮助可怜的汁液,这些汁液必须稍后再来理解。我当时使用的是经典的asp,因此我几乎没有其他选择。

从那以后,我所做的就是功能/过程和linq的组合。通常,总的复杂性小于尝试在一个地方进行的复杂性。将某些条件传递给UDF,这将变得更加易于管理。这为我们提供了易于管理和可理解的结果集。使用linq应用其余的区别。

我们可以同时使用两者的优点:

  • 尽可能减少服务器上的总记录;在服务器上获得尽可能多的疯狂连接。数据库擅长于此。
  • Linq(针对对象等)虽然不那么强大,但是却善于表达复杂的标准。因此将它用于各种可能的区别,这会增加代码的复杂性,但db的处理不会更好。在简化的标准化结果集上运行时,linq可以表达复杂性,而不会降低性能。

如何确定在db中处理哪些条件以及使用linq处理哪些条件?用你的判断。如果我们可以有效地处理复杂的数据库查询,则可以进行处理。部分是艺术,部分是科学。