在C#/。NET3.5中构造动态SQL查询的最佳方法?
我目前正在从事的项目涉及重构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处理哪些条件?用你的判断。如果我们可以有效地处理复杂的数据库查询,则可以进行处理。部分是艺术,部分是科学。