C# 有没有一种简单的方法可以将LINQ中的自定义函数写入实体?
我正在为我的实体框架应用程序编写一个简单的搜索查询。我需要检查一组字段是否为null,如果不是,则对它们调用ToLower()并与搜索查询进行比较。LINQ查询如下所示:C# 有没有一种简单的方法可以将LINQ中的自定义函数写入实体?,c#,linq,entity-framework,linq-to-entities,C#,Linq,Entity Framework,Linq To Entities,我正在为我的实体框架应用程序编写一个简单的搜索查询。我需要检查一组字段是否为null,如果不是,则对它们调用ToLower()并与搜索查询进行比较。LINQ查询如下所示: public IQueryable<Store> SearchStores(string q, IQueryable<Store> source) { q = q.ToLower(); return ( from s in source where (
public IQueryable<Store> SearchStores(string q, IQueryable<Store> source)
{
q = q.ToLower();
return (
from s in source
where (
(s.Name != null && s.Name.ToLower().Contains(q)) ||
(s.Description != null && s.Description.ToLower().Contains(q)) ||
...
}
不过,这当然不起作用,因为LINQ to entities不了解SafeSearch函数是什么:
LINQ to Entities无法识别方法“Boolean SafeSearch(System.String,System.String)”方法,并且无法将此方法转换为存储表达式
有没有一种简单的方法来编写这样一个简单的自定义函数
谢谢 由于linq使用的表达式在实际调用数据库之前不会执行,因此需要将函数封装在谓词中
private static Func<Country, bool> Predicate(string q)
{
return x => (
q.SafeSearch(x.Name) ||
q.SafeSearch(x.Description)
);
}
然后您可以将其与extesion方法一起使用
return source.Where(Predicate(q));
或者使用linq表达式
return from p in source
where Predicate(q).Invoke(p)
select p;
有一种方法可以准备动态查询和条件,也可以使用函数构建其中的一部分。语法也是可读的,对于问题的“简单”部分也可以。可以通过组合Linq表达式来实现。关于如何做到这一点,有几篇文章,但我认为我提出了一种新的方法。至少我没有在网上找到它 要继续,您需要一个包含3个简单函数的库。它们使用
System.Linq.Expressions.ExpressionVisitor
动态修改表达式。其关键功能是统一表达式内的参数,以便使具有相同名称的两个参数变得相同(UnifyParametersByName
)。剩下的部分是用给定的表达式(ReplacePar
)和助手方法(NewExpr
)替换命名参数。该库在github上具有MIT许可证,但您可以自己快速编写一些内容
首先定义一些方法,这些方法稍后可能用于创建动态查询
public class Store
{
...
public static Expression<Func<Store, bool>>
SafeSearchName(string sWhat)
{
return LinqExprHelper.NewExpr(
(Store s) => s.Name != null && s.Name.ToLower().Contains(sWhat)
);
}
public static Expression<Func<Store, bool>>
SafeSearchDesc(string sWhat)
{
return LinqExprHelper.NewExpr(
(Store s) => s.Description != null && s.Description.ToLower().Contains(sWhat)
);
}
}
公共类存储
{
...
公共静态表达式
SafeSearchName(字符串sWhat)
{
返回LinqExprHelper.NewExpr(
(存储s)=>s.Name!=null&&s.Name.ToLower().Contains(sWhat)
);
}
公共静态表达式
SafeSearchDesc(字符串sWhat)
{
返回LinqExprHelper.NewExpr(
(存储s)=>s.Description!=null&&s.Description.ToLower().Contains(sWhat)
);
}
}
然后以这种方式进行查询:
// Define a master condition, using named parameters.
var masterExpr = LinqExprHelper.NewExpr(
(Store s, bool bSearchName, bool bSearchDesc)
=> (bSearchName && bSearchDesc));
// Replace stub parameters with some real conditions.
var combExpr = masterExpr
.ReplacePar("bSearchName", Store.SafeSearchName("b").Body)
.ReplacePar("bSearchDesc", Store.SafeSearchDesc("p").Body);
// Sometimes you may skip a condition using this syntax:
//.ReplacePar("bSearchDesc", Expression.Constant(true));
// It's interesting to see how the final expression looks like.
Console.WriteLine("expr: " + combExpr);
// Execute the query using combined expression.
db.Stores
.Where((Expression<Func<Store, bool>>)combExpr)
.ToList().ForEach(i => { Console.WriteLine(i.Name + ", " + i.Description); });
//使用命名参数定义主条件。
var masterExpr=LinqExprHelper.NewExpr(
(存储s,bool bSearchName,bool bSearchDesc)
=>(bSearchName&&bSearchDesc));
//用一些实际条件替换存根参数。
var combExpr=masterExpr
.ReplacePar(“b搜索名称”,Store.SafeSearchName(“b”).Body)
.ReplacePar(“bSearchDesc”,Store.SafeSearchDesc(“p”).Body);
//有时,您可以使用以下语法跳过某个条件:
//.ReplacePar(“bSearchDesc”,表达式.Constant(true));
//看到最终表达式的样子很有趣。
控制台写入线(“expr:+combExpr”);
//使用组合表达式执行查询。
数据库存储
.其中((表达式)combExpr)
.ToList().ForEach(i=>{Console.WriteLine(i.Name+,“+i.Description);});
我还没有在生产中使用它,但是通过了一些简单的测试。我不认为以这种方式组合查询有任何限制。如果我们需要更多的参数,我们可以附加额外的组合级别。这种方法的优点是,您可以使用内联lambda表达式(易于阅读)以及动态表达式创建和合成(功能非常强大)
到底是“简单”吗?如果您认为LINQ的方法语法很简单,那么这几乎是那么简单。它不允许您创建自定义Linq函数,但提供了类似的功能。数据库上的排序规则类型是什么?这与扩展方法一起工作,但当我在Linq中使用Invoke方法尝试时,我得到:Linq to Entities无法识别方法“Boolean Invoke(Localsip.Models.Wine)”方法,并且此方法无法转换为存储表达式。有什么想法吗?哦,好吧,够了。仍然想知道如何在linq查询中包含“谓词”Func。谢谢您的帮助。@ManicBlowfish您可以从源代码中的p返回。其中(谓词(q))选择p这太错误了。考虑使用LIQKIT及其EF/CUP扩展
public class Store
{
...
public static Expression<Func<Store, bool>>
SafeSearchName(string sWhat)
{
return LinqExprHelper.NewExpr(
(Store s) => s.Name != null && s.Name.ToLower().Contains(sWhat)
);
}
public static Expression<Func<Store, bool>>
SafeSearchDesc(string sWhat)
{
return LinqExprHelper.NewExpr(
(Store s) => s.Description != null && s.Description.ToLower().Contains(sWhat)
);
}
}
// Define a master condition, using named parameters.
var masterExpr = LinqExprHelper.NewExpr(
(Store s, bool bSearchName, bool bSearchDesc)
=> (bSearchName && bSearchDesc));
// Replace stub parameters with some real conditions.
var combExpr = masterExpr
.ReplacePar("bSearchName", Store.SafeSearchName("b").Body)
.ReplacePar("bSearchDesc", Store.SafeSearchDesc("p").Body);
// Sometimes you may skip a condition using this syntax:
//.ReplacePar("bSearchDesc", Expression.Constant(true));
// It's interesting to see how the final expression looks like.
Console.WriteLine("expr: " + combExpr);
// Execute the query using combined expression.
db.Stores
.Where((Expression<Func<Store, bool>>)combExpr)
.ToList().ForEach(i => { Console.WriteLine(i.Name + ", " + i.Description); });