编程语言
首页 > 编程语言> > c# – 在运行时修改linq查询

c# – 在运行时修改linq查询

作者:互联网

问题陈述

假设我有一个搜索人名的查询:

var result = (from person in container.people select person)
             .Where(p => p.Name.Contains(some_criterion)

这将被转换为包含以下like子句的SQL查询:

WHERE NAME LIKE '%some_criterion%'

这有一些性能影响,因为数据库无法有效地使用名称列上的索引(索引扫描v.s.索引搜索,如果我没有记错).

为了解决这个问题,我可以决定只使用StartsWith(),使用like子句生成查询,如:

WHERE NAME LIKE 'some_criterion%'

这使SQL服务器能够以某些功能为代价使用索引查找和交付性能.

我希望能够为用户提供一个选择:默认行为使用StartsWith,但是如果用户希望使用Contains()进行搜索的“增加的灵活性”,那么应该使用.

我试过了什么

我认为这是微不足道的,并继续在字符串上实现了一个扩展方法.但是当然,LINQ不接受这个并抛出异常.

现在,我当然可以使用if或switch语句并为每个案例创建一个查询,但我更倾向于在“更高级别”或更一般地解决这个问题.
简而言之:由于现实应用程序的复杂性,使用if语句来区分用例是不可行的.这会导致很多重复和混乱.我真的希望能够以某种方式封装变化的行为(Contains,StartsWith,EndsWith).

我应该在哪里看,或者我应该寻找什么?这是与IQueryables的可组合性的案例吗?我很困惑!

解决方法:

使用if语句怎么样,而不是过度复杂化?

var query = from person in container.people 
            select person;

if (userWantsStartsWith)
{
    query = from p in query
            where p.Name.Contains(some_criterion)
            select p;
}
else
{
    query = from p in query
            where p.Name.StartsWith(some_criterion)
            select p;
}

更新

如果你真的需要更复杂的东西,可以试试看LinqKit.它可以让你做到以下几点.

var stringFunction = Lambda.Expression((string s1, string s2) => s1.Contains(s2));

if (userWantsStartsWith)
{
    stringFunction = Lambda.Expression((string s1, string s2) => s1.StartsWith(s2));
}

var query = from p in container.people.AsExpandable()
            where stringFunction.Invoke(p.Name, some_criterion)
            select p;

我相信这符合你的要求

I’d really like to be able to encapsulate the varying behavior
(Contains, StartsWith, EndsWith) somehow.

标签:c,linq,entity-framework,extension-methods
来源: https://codeday.me/bug/20190718/1493518.html