LINQ查询表达式和扩展方法有什么区别

发布于 2024-07-18 00:57:16 字数 1292 浏览 5 评论 0 原文

下面是返回相同数据的两个查询。 其他风格我不确定哪个更好。

哪些因素影响这些查询? 使用一种样式相对于另一种样式有什么好处?

样品1

var x = from s in db.Surveys
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID
    join q in db.Questions on sq.Question_ID equals q.ID
    join qg in db.Question_Groups on q.ID equals qg.Question_ID
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type)
    select new { question = sq.Question, status = sq.Status, grp = qg };

样品2

var x = db.Surveys.Where(s => s.Type_ID.Equals(typeID) & s.Type.Equals(type))
              .Join(db.Survey_Questions,
                        s => s.ID,
                        sq => sq.Survey_ID,
                        (s, sq) => new
                        {
                            question = sq.Question,
                            status = sq.Status
                        })
              .Join(db.Question_Groups,
                        q => q.question.ID,
                        qg => qg.Question_ID,
                        (q, qg) => new
                        {
                            question = q.question,
                            status = q.status,
                            group = qg
                        }).ToList();

Below are two queries that return the same data. Other then style I am not sure which is better.

What factors influence these queries?
What are the benefits of using one style over the other?

Sample 1

var x = from s in db.Surveys
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID
    join q in db.Questions on sq.Question_ID equals q.ID
    join qg in db.Question_Groups on q.ID equals qg.Question_ID
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type)
    select new { question = sq.Question, status = sq.Status, grp = qg };

Sample 2

var x = db.Surveys.Where(s => s.Type_ID.Equals(typeID) & s.Type.Equals(type))
              .Join(db.Survey_Questions,
                        s => s.ID,
                        sq => sq.Survey_ID,
                        (s, sq) => new
                        {
                            question = sq.Question,
                            status = sq.Status
                        })
              .Join(db.Question_Groups,
                        q => q.question.ID,
                        qg => qg.Question_ID,
                        (q, qg) => new
                        {
                            question = q.question,
                            status = q.status,
                            group = qg
                        }).ToList();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

梦行七里 2024-07-25 00:57:16

更新:你已经修正了你的标题,所以忽略咆哮。

您的问题标题与您的代码示例无关。 您的问题暗示一种语法是 IEnumerable,另一种语法是 IQueryable,但这是不正确的。 在您的示例中,如果 db.Surveys 是 IQueryable,则您的示例都使用 IQueryable。 我将尝试回答这两个问题

您的两个代码示例只是编写相同 LINQ 查询的不同方式(假设它们写得很好)。 示例 1 中的代码只是示例 2 中的代码的简写。编译器以相同的方式处理两个示例中的代码。 想一想 C# 编译器对待 int? 的方式与 Nullable 相同。 C# 和 VB.Net 语言都提供这种简写查询语法。 其他语言可能没有此语法,您必须使用示例 2 语法。 事实上,其他语言甚至可能不支持扩展方法或 lambda 表达式,而且您还必须使用更丑陋的语法。


更新:

进一步采用 Sander 的示例,当您编写以下内容(查询理解语法)时:

var surveyNames = from s in db.Surveys select s.Name

认为编译器会将简写变成这样(扩展方法和 lambda 表达式):

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name);

但实际上扩展方法和 lambda 表达式是速记自己。 编译器发出类似这样的东西(不完全是这样,只是为了提供一个想法):

Expression<Func<Survey, string>> selector = delegate(Survey s) { return s.Name; };
IQueryable<string> surveryNames = Queryable.Select(db.Surveys, selector);

请注意,Select() 只是 Queryable 类中的一个静态方法。 如果您的 .NET 语言不支持查询语法、lambda 或扩展方法,那么您就必须自己编写代码。


使用一种样式相对于另一种样式有什么好处?

对于小型查询,扩展方法可以更紧凑:

var items = source.Where(s => s > 5);

另外,扩展方法语法可以更灵活,例如条件where子句:

var items = source.Where(s => s > 5);

if(smallerThanThen)
    items = items.Where(s => s < 10);
if(even)
    items = items.Where(s => (s % 2) == 0);

return items.OrderBy(s => s);

另外,有几种方法只能通过扩展方法语法使用(Count()、Aggregate()、Take) ()、Skip()、ToList()、ToArray() 等),所以如果我使用其中之一,我通常会用这种语法编写整个查询,以避免混合这两种语法。

var floridaCount = source.Count(s => s.State == "FL");

var items = source
            .Where(s => s > 5)
            .Skip(5)
            .Take(3)
            .ToList();

另一方面,当查询变得更大、更复杂时,查询理解语法可能会更清晰,尤其是当您开始使用一些 letgroup 进行复杂化时 。

最后,我通常会使用对每个特定查询更有效的方法


更新:您修复了标题,因此忽略其余部分...

现在,关于您的标题:对于 LINQ,IEnumerable 和 IQueryable 非常相似。 它们都有几乎相同的扩展方法(Select、Where、Count 等),主要(唯一?)区别在于 IEnumerable 采用 Func 作为参数,而 IQueryable 采用 < code>Expression> 作为参数。 您以相同的方式表达两者(通常是lambda表达式),但在内部它们完全不同。

IEnumerable 是 LINQ to Objects 的门户。 可以在任何 IEnumerable(数组、列表、可以使用 foreach 进行迭代的任何内容)上调用 LINQ to Objects 扩展方法,并且 Func 会转换为 IL在编译时运行,并在运行时像正常方法代码一样运行。 请注意,其他一些 LINQ 提供程序使用 IEnumerable,因此实际上在幕后使用 LINQ to Objects(LINQ to XML、LINQ to DataSet)。

IQueryable 由 LINQ to SQL、LINQ to Entities 和其他需要检查查询并转换它而不是直接执行代码的 LINQ 提供程序使用。 IQueryable 查询及其 Expression> 在编译时不会编译到 IL 中。 相反,会创建一个表达式树,并且可以在运行时进行检查。 这允许将语句翻译成其他查询语言(例如 T-SQL)。 表达式树可以被编译成Func。 在运行时并根据需要执行。

可以在 这个问题,OP 想要在 SQL Server 中执行 LINQ to SQL 查询的一部分,将对象引入托管代码,并在 LINQ to 中执行其余查询对象。 为了实现这一点,他所要做的就是将 IQueryable 转换为他希望发生切换的 IEnumerable。

Update: You have fixed your title, so ignore the rant.

The title of your question has nothing to do with your code samples. Your question implies that one syntax is IEnumerable and the other is IQueryable, but this is incorrect. In your samples, if db.Surveys is an IQueryable, then both your samples are using IQueryable. I will try to answer both questions.

Your two code samples are just different ways of writing the same LINQ queries (assuming they are well-written). The code in sample 1 is just shorthand for the code in sample 2. The compiler treats the code in both samples the same way. Think of the way the C# compiler will treat int? the same as Nullable<System.Int32>. Both the C# and VB.Net languages provide this shorthand query syntax. Other languages might not have this syntax and you would have to use the sample 2 syntax. In fact, other languages might not even support extension methods or lambda expressions, and you would have to use an uglier syntax yet.


Update:

To take Sander's example further, when you write this (query comprehension syntax):

var surveyNames = from s in db.Surveys select s.Name

You think the compiler turns that shorthand into this (extension methods and lambda expression):

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name);

But actually extension methods and lambda expressions are shorthand themselves. The compilers emits something like this (not exactly, but just to give an idea):

Expression<Func<Survey, string>> selector = delegate(Survey s) { return s.Name; };
IQueryable<string> surveryNames = Queryable.Select(db.Surveys, selector);

Note that Select() is just a static method in the Queryable class. If your .NET language did not support query syntax, lambdas, or extension methods, that is kinda how you would have to write the code yourself.


What are the benefits of using one style over the other?

For small queries, extension methods can be more compact:

var items = source.Where(s => s > 5);

Also, the extension method syntax can be more flexible, such as conditional where clauses:

var items = source.Where(s => s > 5);

if(smallerThanThen)
    items = items.Where(s => s < 10);
if(even)
    items = items.Where(s => (s % 2) == 0);

return items.OrderBy(s => s);

In addition, several methods are only available through extension method syntax (Count(), Aggregate(), Take(), Skip(), ToList(), ToArray(), etc), so if I'll use one of these, I'll usually write the whole query in this syntax to avoid mixing both syntaxes.

var floridaCount = source.Count(s => s.State == "FL");

var items = source
            .Where(s => s > 5)
            .Skip(5)
            .Take(3)
            .ToList();

On the other hand, when a query gets bigger and more complex, query comprehension syntax can be clearer, especially once you start complicating with a few let, group, join, etc.

In the end I will usually use whichever works better for each specific query.


Update: you fixed your title, so ignore the rest...

Now, about your title: With respect to LINQ, IEnumerable and IQueryable are very similar. They both have pretty much the same extension methods (Select, Where, Count, etc), with the main (only?) difference being that IEnumerable takes Func<TIn,TOut> as paremeters and IQueryable takes Expression<Func<TIn,TOut>> as parameters. You express both the same way (usually lamba expressions), but internally they are completely different.

IEnumerable is the doorway to LINQ to Objects. The LINQ to Objects extension methods can be called on any IEnumerable (arrays, lists, anything you can iterate with foreach) and the Func<TIn,TOut> is converted to IL at compile time and runs like a normal method code at run time. Note that some other LINQ providers use IEnumerable and so are actually using LINQ to Objects behind the scenes (LINQ to XML, LINQ to DataSet).

IQueryable is used by LINQ to SQL, LINQ to Entities, and other LINQ providers which need to examine your query and translate it instead of executing your code directly. IQueryable queries and their Expression<Func<TIn,TOut>>s are not compiled into IL at compile time. Instead an expression tree is created and can be examined at run time. This allows the statements to be translated into other query languages (for example T-SQL). An expression tree can be compiled into a Func<TIn,TOut> at run time and executed if desired.

An example that illustrates the difference can be found in this question where the OP wants to do part of a LINQ to SQL query in SQL Server, bring the objects into managed code, and do the rest of the query in LINQ to Objects. To achieve this all he has to do is cast the IQueryable into an IEnumerable where he wants the switch to happen.

我是有多爱你 2024-07-25 00:57:16

LINQ 是一项技术的流行词。

IQueryable 是 LINQ 使用的 .NET 接口。

除了风格之外,两者没有任何区别。 使用您喜欢的任何样式。

我更喜欢第一种风格用于长语句(如此处所示),第二种风格用于非常短的语句。

LINQ is buzz word for a technology.

IQueryable is a .NET Interface which is used by LINQ.

Other than the style, there is no difference between the two. Use whichever style you prefer.

I prefer the first style for long statement (like that one shown here) and the second for very short statements.

-小熊_ 2024-07-25 00:57:16

第一个示例中的 where 子句实际上只是第二个方法中的Where 子句的语法糖。 事实上,您可以编写自己的类,与 Linq 或 IQueryable 无关,只需使用Where 方法,您就可以使用该语法糖。 例如:

    public class MyClass
    {

        public MyClass Where<T>(Func<MyClass, T> predicate)
        {
            return new MyClass { StringProp = "Hello World" };
        }

        public MyClass Select<T>(Func<MyClass, T> predicate)
        {
            return new MyClass ();
        }



        public string StringProp { get; set; }
    }

这显然是一个愚蠢的例子,但请注意,有一个Where方法只返回一个新的MyClass,其中stringprop设置为Hello World。 演示:

MyClass a = new MyClass();
            var q = from p in a
                    where p.StringProp == "foo" // doesnt matter what we put here, as we're not really checking the predicate
                    select p;
            Console.WriteLine(q.StringProp);

这将导致写出“Hello World”。 同样,这个示例显然毫无意义,但它证明了“where”语法只是在代码中查找采用 Func 的Where 方法。

The where clause in the first example is actually just syntactic sugar for the Where clause in your second method. In fact, you can write your own class that has nothing to do with Linq or IQueryable and just by having a Where method, you can use that syntactic sugar. For example:

    public class MyClass
    {

        public MyClass Where<T>(Func<MyClass, T> predicate)
        {
            return new MyClass { StringProp = "Hello World" };
        }

        public MyClass Select<T>(Func<MyClass, T> predicate)
        {
            return new MyClass ();
        }



        public string StringProp { get; set; }
    }

This is obviously a stupid example, but note that there's a Where method that just returns a new MyClass with stringprop set to Hello World. To demonstrate:

MyClass a = new MyClass();
            var q = from p in a
                    where p.StringProp == "foo" // doesnt matter what we put here, as we're not really checking the predicate
                    select p;
            Console.WriteLine(q.StringProp);

This will result in writing out "Hello World". Again, this example is obviously pointless, but it proves the point that the "where" syntax just looks for a Where method in your code that takes a Func.

清君侧 2024-07-25 00:57:16

查询表达式和扩展方法是执行完全相同操作的两种方法。 查询表达式在编译时会转换为扩展方法 - 对于那些更熟悉 SQL 的人来说,它们只是语法糖。

当你这样写时:

var surveyNames = from s in db.Surveys select s.Name;

编译器将其转换为:

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name);

真的,我认为查询表达式只是出于营销原因而创建的 - 一种类似 SQL 的语言构造,在开发 LINQ 时充当引人注目的角色,而不是提供太多实际用途的东西。 我发现大多数人只是直接使用扩展方法,因为它们会产生更统一的编码风格,而不是混合使用 C# 和 SQL。

Query expressions and extension methods are two ways to do the exact same thing. Query expressions get transformed to extension methods when compiling - they are just syntactic sugar for people who are more comfortable with SQL.

When you write this:

var surveyNames = from s in db.Surveys select s.Name;

The compiler transforms this into:

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name);

Really, I think query expressions were just created for marketing reasons - a SQL-like language construct to act as an eye-catcher when LINQ was developed, not something that offers much actual use. I find that most people just use the extension methods directly, as they result in a more unified coding style, instead of a mix of C# and SQL.

z祗昰~ 2024-07-25 00:57:16

1./您的问题标题与您所问的内容不符。
2./你的问题标题确实没有意义。 Linq 代表语言集成查询,是一系列技术和实践的总称,IQueryable 是一个通常用于促进 Linq 的接口。 你正在比较苹果和橙子
3./关于您的实际问题,主要区别在于风格,对于像这样的复杂查询,我个人更喜欢第二个版本,因为它清楚地显示了结果集的进展。

1./ Your question title does not match what you asked.
2./ Your question title does not really make sense. Linq stands for Language Integrated Query and is an umbrella term for a bunch of technologies and practices, IQueryable is an interface that is commonly used to facilitate Linq. you are comparing Apples and Oranges
3./ About your actual question, the main difference is style, for complex queries like this one, my personal preference is the 2nd version, as it clearly shows the progression of the result sets.

月依秋水 2024-07-25 00:57:16

您的 Sample1 是 Linq 的顶级表示,它更具可读性,并且在编译时它将转换为表达式树,即您的 Sample2

var x = from s in db.Surveys
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID
    join q in db.Questions on sq.Question_ID equals q.ID
    join qg in db.Question_Groups on q.ID equals qg.Question_ID
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type)
    select new { question = sq.Question, status = sq.Status, grp = qg };

您可以尝试下面的代码来获取书面查询的表达式

var exp=x.Expression;

当查询不太复杂时使用表达式

Your Sample1 is top level representation of Linq, it is more readable, and while compiling it'll converted to expression tree i.e your Sample2.

var x = from s in db.Surveys
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID
    join q in db.Questions on sq.Question_ID equals q.ID
    join qg in db.Question_Groups on q.ID equals qg.Question_ID
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type)
    select new { question = sq.Question, status = sq.Status, grp = qg };

you can try below code to get expression for written query

var exp=x.Expression;

Expressions are used when query less complicated

十六岁半 2024-07-25 00:57:16

我认为你的问题最好这样表述:“关于 LINQ,IEnumerable 和 IQueryable 之间的区别是什么”

LINQ 查询返回一个 IQueryable 默认情况下。 IQueryable 允许您在执行查询之前将其他过滤器或“子句”附加到查询中。

您的 LINQ 查询(第一个示例)和使用方法链接的 LINQ(第二个示例)产生相同的结果,但语法不同。

可以将 LINQ 查询编写为 LINQ 方法链,反之亦然。 这实际上取决于您的喜好。

@Lucas:不同的是 IEnumerable 执行内存中查询和 IQueryable 内存不足。 这意味着,一旦进入 foreach 迭代器,您就可以使用 IEnumerable,并且在构建查询时,可以通过扩展方法或使用 LINQ from o in object 语法,您正在构建一个 IQueryable。 IQueryable 一旦您触摸枚举器就会执行。

I think your question is better phrased like this, "What is the difference between IEnumerable<T> and IQueryable<T> with respect to LINQ"

LINQ queries return an IQueryable<T> by default. IQueryable<T> allows you to append other filters or "clauses" onto your query before you execute it.

Your LINQ query (first example) and your LINQ using method chaining (second example) produce the same result, with different syntax.

It is possible to write a LINQ query as a LINQ method chain and visa versa. It really depends on your preference.

@Lucas: The different is IEnumerable<T> does in-memory querying and IQueryable<T> does out-of-memory. Meaning, once you are in a foreach iterator, you are using IEnumerable, and when you are building your query, via either extension methods or using LINQ from o in object synatax, you are building an IQueryable<T>. The IQueryable<T> is executed as soon as you touch the Enumerator.

影子的影子 2024-07-25 00:57:16

另一点值得一提的是,Linq 扩展方法遵循 C# 语言,而查询理解内容则像内置于编译器中一样进行预处理。
即您可以导航到 .Select(x =>; 的定义
而你不能 for from ... where ... select

Another point worth mentioning is that the Linq extension methods adhere to C# language whereas the query comprehension stuff is preprocessed like is built into the compiler.
i.e you can navigate to the definition of .Select(x =>
whereas you cannot for from ... where ... select

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文