如果查询DbContext的DbSet,则查询有效,直到DbContext被释放为止。以下将导致例外:
IQueryable<Video> allVideos = null;
using (var context = new MyDbContext())
{
allVideos = context.Videos;
}
var firstVideo = allVideos.first();
显然,使用过的DbSet存储在返回的实现IQueryable的对象中。
但是,MSDN建议(Link)
使用Web应用程序时,请为每个请求使用上下文实例。
当然我可以使用ToList()并将结果作为对象列表返回,但这是不可取的,因为我不知道查询的原因。
示例:假设我的数据库有一个集合国家/地区,这些国家/地区拥有街道,这些街道都有房屋,这些房屋的家庭都有名字。
如果有人要求提供IQueryable,那么他可能会想要搜索英国伦敦唐宁街10号的最老人的名字。
如果我使用ToList()返回序列,将返回所有城市,街道,房屋,人员等,如果他只需要这个人的名字,这将是相当浪费的。延迟执行Linq是件好事。
所以我无法返回ToList(),我必须返回IQueryable。
所以我想做的是打开一个新的DbContext,并以某种方式告诉查询它应该使用新的DbContext:
IQueryable<Video> allVideos = null;
using (var context = new MyDbContext())
{
allVideos = context.Videos;
}
// do something else
using (var context = new MyDbContext())
{
// here some code to attach the query to the new context
var firstVideo = allVideos.first();
}
怎么做?
答案 0 :(得分:0)
当地的大师碰巧路过。他向我解释说,我的设计中的错误是我在使用DbContext时只编写了查询。我的界面应该是这样的,我在实际实现所请求的对象时只需要DbContext。
问题是以下简化版本:
我有一个DbContext,有几个公共DbSet属性。这些属性镜像实际数据库。我想在我的抽象数据库层中隐藏实际的数据库实现,以保护我的数据。我不希望任何人在没有检查这些内容是否正确的情况下访问我更改数据库的内容。
这很简单:只是不要将实际的DbContext暴露给外部世界,但是暴露一个隐藏实际使用的DbContext的外观。这个外观与实际的DbContext进行通信。
对于返回IQueryable的大多数函数,我需要DbContext来访问DbSets。这就是为什么我想创建一个上下文,构造查询和Dispose上下文的原因。但由于延迟执行,仍然需要上下文。
解决方案不是创建自己的上下文,而是让上下文成为函数的参数之一。在这种情况下,外部用户可以调用我的Facade的多个函数来连接查询,甚至可以在DbContext上与Linq查询混合,而无需创建和处理上下文。和其他人一样建议: - 创建上下文 - 调用几个返回查询的函数 - 使用ToList()/ ToArray()/ First()/ Count()等执行查询。 - 处理上下文
Asn扩展方法
public static IQueryable<Video> GetObsoleteVideos(this MyDbContext context)
{
// perform several difficult Linq statements on context
return ...
}
用法:
using (var myContext = new MyDbContext())
{
var difficultQuery = myContext.GetObsoleteVideos()
.Where(video => ....)
.GetBoxingVideos() // another extension method
.Take(10);
// query still deferred
var result = difficultQuery.ToList()
}
这种方式(特别是如果我创建接口)我能够禁止访问我的DBSets。我甚至可以在内部重新组织我的Db和DbContext,而无需外部用户注意任何事情。
答案 1 :(得分:-1)
对象上下文中有方法可以执行此操作:
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
objectContext.Detach(entity);
objectContext.Attach(entity);
但是,正如MSDN引用中所述,您应该为每个请求使用一个EF上下文实例。这指的是HttpRequest不是单个查询。当您在一个请求中执行操作时,不应该在EF上下文周围使用块,并且应该延长其生命周期。对于新请求,建议不要跨越请求保持状态,而是遵循协议