我可以在LINQ查询中使用扩展方法吗? [英] Can I use an extension method inside a LINQ query?

查看:77
本文介绍了我可以在LINQ查询中使用扩展方法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

    public QuestionDetail GetQuestionDetail(int questionId)
    {
        Question question = _questionsRepository.GetById(questionId);
        QuestionDetail questionDetail = new QuestionDetail()
        {
            QuestionId = questionId,
            Text = question.Text.FormatCode()
        };
        return questionDetail;
    }

我将其替换为:

    public QuestionDetail GetQuestionDetail(int questionId)
    {
        var questions = _questionsRepository
            .GetAll()
            .Include(q => q.Answers)
            .Select(m => new QuestionDetail
            {
                QuestionId = m.QuestionId,
                Text = m.Text.FormatCode()
            })
            .FirstOrDefault();

        return questions;
    }

现在,我收到以下错误消息:

LINQ to Entities does not recognize the method 'System.String FormatCode(System.String)' 
method, and this method cannot be translated into a store expression.

这是我的FormatCode()

Here's my FormatCode()

public static class CodeDisplay {

    public static string FormatCode(this string content)
    {
        var data1 = content
            .Split(new[] { "<pre>", "</pre>" }, StringSplitOptions.None);
        var data2 = data1
            .Select((s, index) =>
            {
                string s1 = index % 2 == 1 ? string.Format("{0}{2}{1}",
                    "<table class='code'>", "</table>", SplitJoin(s)) : s;
                return s1;
            });
        var data3 = data2.Where(s => !string.IsNullOrEmpty(s));
        var data4 = string.Join("\n", data3);
        return data4;
    }

    private static string SplitJoin(string content)
    {
        IEnumerable<String> code =
            content.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)
                .Select((line, index) =>
                    string.Format("<tr><td>{0}</td><td><pre><code>{1}</code></pre></td></tr>\n",
                    (index + 1).ToString("D2"), HttpUtility.HtmlEncode(line)));
        return string.Join("", code) + "\n";
    }


}

推荐答案

简短的回答:是的,您可以在LINQ查询中使用自定义扩展方法-但是您不能使用基础数据提供者不知道如何扩展的方法执行.

Short answer: Yes, you can use a custom extension method inside a LINQ query - but you cannot use an extension method that the underlying data provider does not know how to execute.

LINQ代表语言集成查询,并且是C#中的语言功能.您可以在LINQ查询中使用任何.NET方法.这样的LINQ并不了解基础数据存储,其详细信息通过IEnumerable<T>IQueryable<T>接口向LINQ公开.当您在查询实现IQueryable<T>的对象(例如实体框架表)时,该接口将公开底层的LINQ提供程序,该提供程序知道在Entity Framework/SQL中进行查询.

LINQ stands for Language-Integrated-Query, and is a language feature in C#. You can use any .NET method in a LINQ query. LINQ as such does not know about the underlying data store, the details of which is exposed to LINQ via the IEnumerable<T> or IQueryable<T> interfaces. When you are querying against an object that implements IQueryable<T>, such as an Entity Framework Table, the interface exposes the underlying LINQ provider, that knows about querying in Entity Framework / SQL.

在查询中使用任何方法时,.NET方法都必须转换为基础数据提供程序,此方法才能起作用.对于LINQ-to-Objects(不涉及数据库),此转换是微不足道的(即,无需转换),因此您可以使用任何扩展方法.对于LINQ-to-SQL或LINQ-to-Entities(如您所用),基础数据提供者必须知道如何将CLR方法转换为基础存储中的表示形式,例如SQL.这是LINQ提供程序的工作.

When using any method in a query, the .NET method must have a conversion to the underlying data provider, for this to work. For LINQ-to-Objects (where no database is involved), this conversion is trivial (ie. no conversion needed), so you can use any extension methods. For LINQ-to-SQL, or LINQ-to-Entities (as you are using), the underlying data provider must know how to translate the CLR method to a representation in the underlying storage, such as SQL. This is the job of LINQ providers.

因此,您不能在LINQ-to-Entities查询中使用自定义扩展方法.为此,LINQ提供程序需要知道如何用SQL表示您的方法,而它并不知道.

Therefore, you cannot use a custom extension method inside your LINQ-to-Entities query. For that to work, the LINQ provider would need to know how to represent your method in SQL, and it does not know that.

无论如何,实现此目的的一种常见方法是,通过调用诸如ToArray()ToList()这样的急切方法之一,在基础数据提供程序中执行查询,然后使用自定义方法进一步优化查询.因为结果是简单的CLR对象,所以使用LINQ-to-Objects,并且您可以使用自定义CLR方法.请注意,这可能会从数据库中获取许多结果.对于您的示例,您仅获取一个结果,因此这无关紧要.

A common way to achieve this anyway, is to execute the query in the underlying dataprovider by calling one of the eager methods such as ToArray() or ToList(), and then further refining the query after that with your custom method. Because the result is simple CLR objects, LINQ-to-Objects is used, and you can use your custom CLR method. Just be aware that this could potentially fetch many results from the database. For your example, you are only fetching one result, so this does not matter.

将提到的模式应用于您的代码将如下所示:

Applying the mentioned pattern to your code would look like this:

public QuestionDetail GetQuestionDetail(int questionId)
{
    var questions = _questionsRepository
        .GetAll()
        .Include(q => q.Answers)
        .Take(1)   // Constrain to one result fetched from DB
        .ToArray() // Invoke query in DB
        .Select(m => new QuestionDetail
        {
            QuestionId = m.QuestionId,
            Text = m.Text.FormatCode()
        })
        .FirstOrDefault();

    return questions;
}

这篇关于我可以在LINQ查询中使用扩展方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆