简体   繁体   English

Linq中的IQueryable,IEnumerable和列表

[英]IQueryable, IEnumerable and Lists in Linq

I'm experimenting with some queries to find out the best way to get performance gains. 我正在尝试一些查询,以找出获得性能提升的最佳方法。

I know that using IQueryable is preferable to performing Linq to Sql or Linq to Entity database queries and that IEnumerable is best used for linq to Objects, Linq to xml, and in memory processing. 我知道使用IQueryable优于执行对SQL的Linq或对实体数据库查询的Linq,并且IEnumerable最适合对对象进行linq,对xml进行Linq以及在内存处理中使用。

I have a linq query as follows on my WCF service. 我在WCF服务上有一个linq查询,如下所示。 When I try and modify the Controller method that calls this, I get the following design time compile error: 当我尝试修改调用此方法的Controller方法时,出现以下设计时编译错误:

Cannot implicitly convert type 'YeagerTechModel.DropDownLists.ProjectDescription[]' to 'System.Linq.IQueryable' 无法将类型'YeagerTechModel.DropDownLists.ProjectDescription []'隐式转换为'System.Linq.IQueryable'

Note that the ProjectDescription object is defined as follows: 请注意,ProjectDescription对象的定义如下:

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;

namespace YeagerTechModel.DropDownLists
{
    [DataContract]
    [Serializable]
    public partial class ProjectDescription
    {
        [DataMember]
        public Int16 ProjectID { get; set; }
        [DataMember]
        public String Description { get; set; }
    }
}

Here is the DB method call: 这是数据库方法调用:

public IQueryable<ProjectDescription> GetProjectDropDownList()
        {
            try
            {
                using (YeagerTechEntities DbContext = new YeagerTechEntities())
                {
                    DbContext.Configuration.ProxyCreationEnabled = false;
                    DbContext.Database.Connection.Open();

                    IQueryable<ProjectDescription> project = DbContext.Projects.Where(w => w.Notes != null).Select(s =>
                        new ProjectDescription()
                        {
                            ProjectID = s.ProjectID,
                            Description = s.Description
                        }
                    );
                    return project;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

Here is the code in the Controller method: 这是Controller方法中的代码:

IQueryable<ProjectDescription> projectDdl = db.GetProjectDropDownList();

Now, prior to this experimentation after reading up on the performance gains of IQueryable, etc, the original method to get the data from the database was as follows: 现在,在阅读完IQueryable等的性能提升之后的本实验之前,从数据库获取数据的原始方法如下:

public List<ProjectDescription> GetProjectDropDownList()
        {
            try
            {
                using (YeagerTechEntities DbContext = new YeagerTechEntities())
                {
                    DbContext.Configuration.ProxyCreationEnabled = false;
                    DbContext.Database.Connection.Open();

                    var project = DbContext.Projects.Where(w => w.Notes != null).Select(s =>
                        new ProjectDescription()
                        {
                            ProjectID = s.ProjectID,
                            Description = s.Description
                        }
                    );

                    List<ProjectDescription> myProjects = new List<ProjectDescription>();

                    myProjects = project.ToList();

                    return myProjects;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

The code in the Controller was as follows: 控制器中的代码如下:

IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList();

First question is: Many queries use the var keyword to infer the type coming back. 第一个问题是:许多查询使用var关键字来推断返回的类型。 Which one to use when calling the DB to retrieve records? 调用数据库检索记录时使用哪个? The "var" syntax or the "IQuerable" syntax"? “ var”语法还是“ IQuerable”语法”?

The second thing I noticed is that on the Controller side, for a collection, it always expects a List object which is easily converted to IEnumerable. 我注意到的第二件事是,在控制器方面,对于一个集合,它总是希望有一个List对象,该对象很容易转换为IEnumerable。

So, based on this premise, I gather that my optimum solution would be as follows: For the DB method call: 因此,基于此前提,我得出的最佳解决方案如下:对于DB方法调用:

public List<ProjectDescription> GetProjectDropDownList()
        {
            try
            {
                using (YeagerTechEntities DbContext = new YeagerTechEntities())
                {
                    DbContext.Configuration.ProxyCreationEnabled = false;
                    DbContext.Database.Connection.Open();

                    IQueryable<ProjectDescription> project = DbContext.Projects.Where(w => w.Notes != null).Select(s =>
                        new ProjectDescription()
                        {
                            ProjectID = s.ProjectID,
                            Description = s.Description
                        }
                    );

                    List<ProjectDescription> myProjects = new List<ProjectDescription>();

                    myProjects = project.ToList();

                    return myProjects;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

For the code snippet in the Controller, it should be as follows and everything works fine: 对于Controller中的代码段,应如下所示,一切正常:

IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList();

So, if IQueryable gives better performance (specifically on filtering and supports lazy loading), why not use the last DB method instead of the "var" keyword? 因此,如果IQueryable提供了更好的性能(特别是在筛选上并支持延迟加载),为什么不使用最后一个DB方法而不是“ var”关键字呢?

Can somebody help explain what should be the optimum scenario? 有人可以帮助解释什么是最佳方案吗?

Whether you use var or take the time to type out the variable's type isn't really an issue. 无论您使用var还是花时间键入变量的类型,都不是真正的问题。 Your second and third examples both compile into exactly the same code. 您的第二个和第三个示例都编译成完全相同的代码。

Your first implementation, however, is much better than the other two. 但是,您的第一个实现比其他两个好得多。 Your first method return a query . 您的第一个方法返回一个查询 The other two return the results of that query . 其他两个返回该查询的结果

So the first implementation allows the caller to apply further filters/mappings/manipulations of that query and have them be reflected in the database query that is called, rather than on the results in memory . 因此,第一种实现允许调用者对该查询应用进一步的过滤器/映射/操作, 并使它们反映在所调用的数据库查询中,而不是内存中的结果上 It also means that you're deferring actually executing that query until later on when you need it, rather than right now. 这也意味着您将实际执行该查询的时间推迟到以后需要它时,而不是现在。

That implementation does have a flaw though; 但是该实现确实存在缺陷。 you're deferring execution but also disposing of the underlying context before the query is executed. 您不仅要推迟执行,还要在执行查询之前处理基础上下文。 You'll need to scope your context at a "higher" level to ensure that it has not yet been disposed of until after the query has been executed. 您需要将上下文范围限定在“较高”级别,以确保在执行查询之后才将其释放。

As for the error, you haven't shown enough information to see where the problem lies, but you should make an effort to fix it without just doing all of your data manipulation in your application instead of in your database. 至于错误,您没有显示足够的信息来查看问题的根源,但是您应该努力解决问题,而不仅仅是在应用程序而不是数据库中进行所有数据操作。

Side note: there's no point in catching an exception just to rethrow it. 旁注:捕获异常只是为了重新抛出异常是没有意义的。 You're doing nothing productive but clearing out the stack trace. 您什么都没有做,只是清除堆栈跟踪。 Just don't catch the exception in the first place if you have nothing to do with it. 如果您与异常无关,请不要首先捕获该异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM