C# 有没有一种简单的方法可以将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 (

我正在为我的实体框架应用程序编写一个简单的搜索查询。我需要检查一组字段是否为null,如果不是,则对它们调用ToLower()并与搜索查询进行比较。LINQ查询如下所示:

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); });