无法返回类型IQueryable或IEnumerable

sag*_*y36 5 c# linq asp.net-mvc wcf entity-framework

由于我无法从Linq到Entities查询返回这些类型中的任何一种,因此我坚持返回List.

从DB调用返回时(在单独的WCF服务或DLL中),Controller中的代码失败,因为dbcontext连接已关闭.

请注意以下代码.对于IEnumerable和IQueryable,由于以上描述,数据不会返回.

MVC控制器中的方法

// Controller
IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList().AsEnumerable();
// Error coming back because dbcontext connection was closed.
ViewBag.ProjectsCust = new SelectList(projectDdl, "ProjectId", "Name");
Run Code Online (Sandbox Code Playgroud)

WCF服务或DLL中的方法

// WCF Service or DLL 
public IEnumerable<ProjectDescription> GetProjectDropDownList()
{
    try
    {
        //IQueryable<ProjectDescription> project = null;

        using (YeagerTechEntities DbContext = new YeagerTechEntities())
        {
            DbContext.Configuration.ProxyCreationEnabled = false;
            DbContext.Database.Connection.Open();

            IEnumerable<ProjectDescription> project = DbContext.Projects.Select(s =>
                new ProjectDescription()
                {
                    ProjectID = s.ProjectID,
                    Description = s.Description
                }
            );


            return project;
        }


    }
    catch (Exception ex)
    {
        throw ex;
    }
}
Run Code Online (Sandbox Code Playgroud)

我甚至尝试在DB调用之前建立一个DbContext实例,但实际上仍然没有尝试将DbContext传递给DB方法.

控制器:

DbContext = new YeagerTechEntities();
IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList(DbContext).AsEnumerable();
ViewBag.ProjectsCust = new SelectList(projectDdl, "ProjectId", "Name");

DbContext.Dispose();
Run Code Online (Sandbox Code Playgroud)

数据库方法:

public IEnumerable<ProjectDescription> GetProjectDropDownList(YeagerTechEntities DbContext)
{
    try
    {
        //IQueryable<ProjectDescription> project = null;


            DbContext.Configuration.ProxyCreationEnabled = false;
            DbContext.Database.Connection.Open();

            IEnumerable<ProjectDescription> project = DbContext.Projects.Select(s =>
                new ProjectDescription()
                {
                    ProjectID = s.ProjectID,
                    Description = s.Description
                }
            );


            return project;
        }


    catch (Exception ex)
    {
        throw ex;
    }
}
Run Code Online (Sandbox Code Playgroud)

除了使用List之外唯一有效的方法是将DB方法实际放在Controller中,这显然不是一个好的做法.

以下是可以正常工作的List约定:

控制器:

IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList();
                ViewBag.ProjectsCust = new SelectList(projectDdl, "ProjectId", "Name");
Run Code Online (Sandbox Code Playgroud)

数据库方法:

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

            IEnumerable<ProjectDescription> project = DbContext.Projects.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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果有人能够向我解释使用IQueryable或IEnumerable时应该是什么样的正确模型,那就没问题了.但是,在阅读此链接后,看起来似乎是List的方法: IEnumerable vs IQueryable for Business Logic或DAL返回类型

Ste*_*rne 9

使用IEnumerable/IQueryable时代码失败的原因是因为EF查询被延迟; 也就是说,在你开始枚举(foreach等)或"实现"(ToList()等)结果之前,它实际上并没有对数据库执行.

  • 因此,因为你创建一个有效的温度DbContext与你using{}时,IEnumerable你传递出的功能是一个地雷-底层的DbContext杜绝使用块之后存在的,任何试图枚举或物化的收集将失败.

  • 即使您在DBContext没有使用块的情况下创建了Dispose它,然后在执行查询之前继续执行它 - 因此得到相同的错误.

  • 这是不IQueryable从DAL/Repository 返回的主要原因之一- 因为收件人无法知道查询所依赖的底层上下文在尝试使用结果之前是否已关闭.IEnumerable更好(当然是List<T>实现IEnumerable<T>)和恕我直言列表更好,因为它强制您返回一个完全物化的集合,并使调用者明白结果不再连接到数据库.

  • 所以你拥有的工作版本可能很好 - 创建你的上下文,执行查询然后立即实现它执行实际的SQL,然后断开结果集与数据库的连接.所以这种模式对你来说很好.

  • 但是我建议使用像Ninject这样的IoC容器为你注入像DbContext这样的东西,因为它让你不必担心你的DbContexts的生命周期.

希望有所帮助.