【问题标题】:IQueryable, IEnumerable and Lists in LinqLinq 中的 IQueryable、IEnumerable 和列表
【发布时间】:2013-10-18 19:51:49
【问题描述】:

我正在尝试一些查询,以找出获得性能提升的最佳方法。

我知道使用 IQueryable 比执行 Linq to Sql 或 Linq to Entity 数据库查询更可取,并且 IEnumerable 最适合用于 linq to Objects、Linq to xml 和内存处理。

我的 WCF 服务上有如下 linq 查询。当我尝试修改调用它的 Controller 方法时,我收到以下设计时编译错误:

无法将类型“YeagerTechModel.DropDownLists.ProjectDescription[]”隐式转换为“System.Linq.IQueryable”

注意,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; }
    }
}

这里是 DB 方法调用:

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

这是Controller方法中的代码:

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

现在,在阅读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;
            }
        }

Controller中的代码如下:

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

第一个问题是: 许多查询使用 var 关键字来推断返回的类型。调用数据库检索记录时使用哪一个? “var”语法还是“IQerable”语法?

我注意到的第二件事是,在 Controller 端,对于一个集合,它总是需要一个可以轻松转换为 IEnumerable 的 List 对象。

因此,基于这个前提,我认为我的最佳解决方案如下: 对于 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;
            }
        }

对于Controller中的代码sn-p,应该如下,一切正常:

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

那么,如果 IQueryable 提供更好的性能(特别是在过滤和支持延迟加载方面),为什么不使用最后一个 DB 方法来代替“var”关键字呢?

有人可以帮助解释什么是最佳方案吗?

【问题讨论】:

    标签: c# linq-to-sql collections linq-to-entities entity-framework-5


    【解决方案1】:

    您是使用var 还是花时间输入变量的类型都不是问题。您的第二个和第三个示例都编译成完全相同相同的代码。

    但是,您的第一个实现比其他两个要好得多。您的第一个方法返回查询。其他两个返回该查询的结果

    所以第一个实现允许调用者对该查询应用进一步的过滤器/映射/操作并将它们反映在被调用的数据库查询中,而不是在内存中的结果中。这也意味着您将实际执行该查询推迟到以后需要它时,而不是现在。

    该实现确实存在缺陷;您要推迟执行,还要在执行查询之前处理底层上下文。您需要在“更高”级别确定上下文的范围,以确保在执行查询之前它还没有被释放。

    至于错误,您没有提供足够的信息来查看问题所在,但您应该努力修复它,而不仅仅是在您的应用程序中而不是在您的数据库中进行所有数据操作。

    旁注:捕获异常只是为了重新抛出它是没有意义的。除了清除堆栈跟踪之外,您没有做任何有效的事情。如果您与它无关,请不要首先捕获异常。

    【讨论】:

    • 感谢您的回答。但是,调用 DB 方法的第一个实现的 Controller 方法不接受返回 IQueryable 结果。它总是期望 ProjectDescription 对象是 List 类型。
    • 这就是为什么我推迟并说根据我之前的评论,我最好的选择是最后一个。
    • 如果我知道如何让 Controller 中的代码接受来自 ProjectDescription 对象的 IQueryable 结果,我同意第一个实现是最好的......
    • @sagesky36 如果该方法的某个特定调用者需要一个列表,那么它可以在结果上调用ToList 以将其具体化为一个列表。不过,方法本身不需要这样做。
    • Servy,如果我在 Controller 中将代码 sn-p 设置为“IQueryable projectDdl = db.GetProjectDropDownList();”那是我得到设计时编译错误的时候。它只接受 IEnumerable 或 List 的返回类型。如果您知道如何让它接受 IQueryable 结果,请务必告诉我。
    猜你喜欢
    • 2022-08-18
    • 1970-01-01
    • 2020-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    相关资源
    最近更新 更多