[英]IQueryable, IEnumerable and Lists in Linq
我正在尝试一些查询,以找出获得性能提升的最佳方法。
我知道使用IQueryable优于执行对SQL的Linq或对实体数据库查询的Linq,并且IEnumerable最适合对对象进行linq,对xml进行Linq以及在内存处理中使用。
我在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; }
}
}
这是数据库方法调用:
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;
}
}
控制器中的代码如下:
IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList();
第一个问题是:许多查询使用var关键字来推断返回的类型。 调用数据库检索记录时使用哪个? “ var”语法还是“ IQuerable”语法”?
我注意到的第二件事是,在控制器方面,对于一个集合,它总是希望有一个List对象,该对象很容易转换为IEnumerable。
因此,基于此前提,我得出的最佳解决方案如下:对于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中的代码段,应如下所示,一切正常:
IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList();
因此,如果IQueryable提供了更好的性能(特别是在筛选上并支持延迟加载),为什么不使用最后一个DB方法而不是“ var”关键字呢?
有人可以帮助解释什么是最佳方案吗?
无论您使用var
还是花时间键入变量的类型,都不是真正的问题。 您的第二个和第三个示例都编译成完全相同的代码。
但是,您的第一个实现比其他两个要好得多。 您的第一个方法返回一个查询 。 其他两个返回该查询的结果 。
因此,第一种实现允许调用者对该查询应用进一步的过滤器/映射/操作, 并使它们反映在所调用的数据库查询中,而不是内存中的结果上 。 这也意味着您将实际执行该查询的时间推迟到以后需要它时,而不是现在。
但是该实现确实存在缺陷。 您不仅要推迟执行,还要在执行查询之前处理基础上下文。 您需要将上下文范围限定在“较高”级别,以确保在执行查询之后才将其释放。
至于错误,您没有显示足够的信息来查看问题的根源,但是您应该努力解决问题,而不仅仅是在应用程序而不是数据库中进行所有数据操作。
旁注:捕获异常只是为了重新抛出异常是没有意义的。 您什么都没有做,只是清除堆栈跟踪。 如果您与异常无关,请不要首先捕获该异常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.