我是一个修改Web API和实体框架6的SQL人员,我一直收到错误"由于已经处理了DbContext,因此无法完成操作"当我的代码是:
namespace DataAccessLayer.Controllers
{
public class CommonController : ApiController
{
[Route("CorrespondenceTypes")]
[HttpGet]
public IQueryable GetCorrespondenceTypes()
{
using (var coreDB = new coreEntities())
{
var correspondenceType = coreDB.tblCorrespondenceTypes.Select(cor => new { cor.CorrespondenceTypeName });
return correspondenceType;
}
}
}
}
但是,如果稍微更改我的代码并试一试,那就可以了:
namespace DataAccessLayer.Controllers
{
public class CommonController : ApiController
{
readonly coreEntities coreDB = new coreEntities();
[Route("CorrespondenceTypes")]
[HttpGet]
public IQueryable GetCorrespondenceTypes()
{
var correspondenceType = coreDB.tblCorrespondenceTypes.Select(cor => new { cor.CorrespondenceTypeName });
return correspondenceType;
}
}
}
我的问题是为什么第二个工作但不是第一个?是否更好的做法是每次都有一个全局连接字符串或显式调用DBContext?
答案 0 :(得分:3)
您正在收到错误,因为您正在返回尚未执行查询的IQueryable,并且在需要执行该查询时已经处理了DbContext。
记住实体框架在初始化集合或任何不支持延迟执行的方法之前不会执行查询。访问this链接以获取Linq延迟执行支持方法的列表。
为什么第二个工作但不是第一个工作?
在第一个代码片段中,您将返回一个未执行DbQuery的IQuerable实例,然后在它上面触发对您的上下文(coreDB
)的dispose。所以,每当你的代码迭代集合时,它会尝试触发DbQuery,但发现上下文已经被破坏,所以你得到一个错误。
在第二种情况下,当您迭代集合coreDB
时,上下文必须处于活动状态,这样您就不会收到错误。
更好的做法是每次都有一个全局连接字符串或显式调用DBContext吗?
这个问题的答案是基于开发者的品味或他自己的舒适。您可以使用包含在using语句中的上下文,如下所示:
public IList GetCorrespondenceTypes()
{
using (var coreDB = new coreEntities())
{
var correspondenceType = coreDB.tblCorrespondenceTypes.Select(cor => new { cor.CorrespondenceTypeName });
return correspondenceType.ToList();
}
}
如上面的代码段所示,如果您在返回之前使用ToList
,则会在coreDB
被销毁之前执行查询。在这种情况下,您必须确保返回物化响应(即在执行DbQuery后返回响应)。
注意:我注意到大多数人选择第二种方式。其中将context作为实例字段或属性。