5

由于我无法从 Linq 到实体查询中返回这两种类型中的任何一种,因此我坚持返回一个列表。

从 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");

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

我什至尝试在 DB 调用之前建立一个 DbContext 实例,但实际上尝试将 DbContext 传递给 DB 方法仍然无效。

控制器:

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

DbContext.Dispose();

数据库方法:

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

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

这是正常工作的 List 约定:

控制器:

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

数据库方法:

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

如果有人可以向我解释使用 IQueryable 或 IEnumerable 时正确的模型应该是什么,那很好。但是,在阅读了这个链接之后,看起来 List 绝对是要走的路: IEnumerable vs IQueryable for Business Logic or DAL return Types

4

2 回答 2

9

使用 IEnumerable/IQueryable 时您的代码失败的原因是因为 EF 查询被延迟;也就是说,直到您开始枚举(foreach等)或“具体化”(ToList()等)结果,它实际上并没有针对数据库执行。

  • 因此,因为您使用 . 创建了一个有效的 temp DbContextusing{}所以IEnumerable您从函数中传递出来的 .

  • 即使您在DBContext没有 using 块的情况下创建了该块,您也会在Dispose执行查询之前继续执行它 - 因此会出现相同的错误。

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

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

  • 但是,我建议您使用 IoC 容器(例如Ninject )为您注入 DbContext 之类的东西,因为它使您不必担心 DbContext 的生命周期。

希望有帮助。

于 2013-10-22T18:28:00.777 回答
2

如您所知,您DbContext可以查询您的数据库,因此当 SQL 请求发送到您的 SGBD 时,它必须处于活动状态。

这里的关键是要准确了解IQueryable的工作原理:

IQueryable 接口继承了 IEnumerable 接口,因此如果它表示一个查询,则可以枚举该查询的结果。枚举导致与要执行的 IQueryable 对象关联的表达式树。“执行表达式树”的定义特定于查询提供程序。例如,它可能涉及将表达式树转换为底层数据源的适当查询语言。

这意味着只要您的 Linq 查询没有被枚举(使用 .ToList() 或 foreach),就不会向数据库发送查询。执行被推迟!

在您的第一次尝试中,您是:

  • 调用GetProjectDropDownList方法
  • 返回一个IEnumerable(这是一个 Ling 查询)而不“枚举”它
  • 处置DbContext
  • 在生成视图时枚举您的 Linq 查询,new SelectList但是...您DbContext当时已经被处理掉了。

这同样适用于您的第二次尝试,DbContext稍后会被处理,但在生成视图时也已经被处理。

在您最后一次尝试中,一切正常,因为您DbContext在枚举 Linq 查询时仍然活着(使用project.ToList();

在我看来,将您的DbContext调用和实例隔离到数据访问层并返回列表或简单的断开连接的对象根本不是一个坏习惯。

于 2013-10-22T18:39:54.800 回答