首页 > 解决方案 > 在 EF 6.4.4 的查询中使用多种方法

问题描述

我有在查询中使用的扩展方法。以下是方法:

public static class UOMExtensions
    {
        public static UOM GetSourceUOM(this UOM uOM)
        {
            //Calculate something
            return uOM;
        }

        public static UOM GetParentUOM(this UOM uOM)
        {
            var sourceUOM = uOM.GetSourceUOM();
            //Do something recoursively
            return sourceUOM;
        }

        public static bool IsCorrectUOM(this UOM uOM)
        {
            var parent = uOM.GetParentUOM();
            //Do something
            return true;
        }
    }

这是我的查询:

 using (Context context = new Context())
        {
            var uoms = context.Set<UOM>().Where(a => a.IsCorrectUOM()).ToList();
        }

我得到了这个例外:

System.NotSupportedException: 'LINQ to Entities 无法识别方法'Boolean >IsCorrectUOM(ConsoleApp1.UOM)' 方法,并且此方法无法转换为存储表达式。

之后,我尝试使用以下方法创建表达式NJection.LambdaConverter

public static bool IsCorrectUOMMethod(UOM uOM)
    {
        var parent = uOM.GetParentUOM();
        //Do something
        return true;
    }

    public static Expression<Func<UOM, bool>> IsCorrectUOMExression()
    {
        var lambda = Lambda.TransformMethodTo<Func<UOM, bool>>()
                       .From(() => IsCorrectUOMMethod)
                       .ToLambda();
        return lambda;
    }

我的查询变成了:

using (Context context = new Context())
        {
            var uoms = context.Set<UOM>().Where(UOMExtensions.IsCorrectUOMExression()).ToList();
        }

之后我得到了这个例外:

System.NotSupportedException:“‘Block’类型的未知 LINQ 表达式。”

如何成功执行我的查询?我无法更改或删除我的方法,因为它们做复杂的事情并且有很多用途。

标签: c#entity-frameworklinqlambda

解决方案


您必须了解 IEnumerable 和 IQueryable 之间的区别。

一个实现 IEnumerable 的对象代表一个序列:你可以得到序列的第一个元素,一旦你得到一个元素,你就可以请求序列中的下一个元素。

在最低级别,这是使用 GetEnumerator() 并重复 MoveNext() / Current 完成的。foreach、ToList()、Any()、Count() 等将深入使用这些方法。

然而,一个 IQueryable 并不代表序列本身,它代表创建序列的潜力

为此,IQueryable 包含一个表达式和一个提供程序。表达式是对必须设置哪些数据的一般描述。Provider 知道谁必须提供数据(通常是数据库管理系统),以及使用什么语言与 DBMS(通常是 SQL)进行通信。

只要您连接返回的 LINQ 语句IQueryable<...>,您只是在更改表达式。只有当您开始枚举时,无论是使用 GetEnumerator / MoveNext 还是更高级别:foreach、ToList 等,Expression 才会发送给 Provider,后者会将其翻译成 SQL 并执行查询。返回的数据表示为一个可枚举的序列。

问题是提供者不知道你的方法GetSourceUOMGetParentUOM等。因此它不能将它们翻译成 SQL。事实上,有几个 LINQ 方法也不能使用。请参阅支持和不支持的 LINQ 方法

回到你的问题

您可以做的是转换您的扩展方法,使其扩展IQueryable<UOM>.

    public static IQueryable<UOM> WhereCorrectUOM(this IQueryable<UOM> source)
    {
        IQueryable<UOM> parents = source.ToParentUoms();
        // Do something with parents to decide whether to return true or false
        // for example:
        return parents.Where(parent => parent.IsCorrect).Any();
    }

    public static IQueryable<UOM> ToParentUoms(this IQueryable<UOM> source)
    {
        IQueryable<UOM> parentUoms = source.Select(item => ...)
        return parentUoms;
    }

    public static IQueryable<UOM> ToSourceUoms(this IQueryable<UOM> source)
    {
        //Calculate something
        IQueryable<UOM> sourceUoms = source.Select(item => ...)
        return sourceUoms;
    }

唉,你忘了提到你的实际代码,所以你必须自己填写。重要的是您只能调用支持的 LINQ 和 .NET 方法,或者您自己的IQueryable<UOM>.


推荐阅读