简体   繁体   中英

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.

I have a linq query as follows on my WCF service. When I try and modify the Controller method that calls this, I get the following design time compile error:

Cannot implicitly convert type 'YeagerTechModel.DropDownLists.ProjectDescription[]' to 'System.Linq.IQueryable'

Note that the ProjectDescription object is defined as follows:

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:

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:

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. Which one to use when calling the DB to retrieve records? The "var" syntax or the "IQuerable" syntax"?

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.

So, based on this premise, I gather that my optimum solution would be as follows: For the DB method call:

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:

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?

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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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