非 EF 实体的“已释放对象上下文实例”
本文关键字:对象 上下文 实例 释放 EF 实体 | 更新日期: 2023-09-27 18:21:15
我正在使用Entity Framework 6
通过返回Complex
对象的存储过程查询一些对象。在将这些对象返回给客户端之前,我将它们"转换"为特定于客户端的实体。
在服务器端,我有以下代码从数据库中获取 DBMeeting
类型的复杂对象:
public static IEnumerable<Meeting> GetMeetings()
{
using(var context = new MyDataContext())
{
var dbMeetings = context.GetMeetings(null, null);
var result = ComplexToEntityTranslator.TranslateMeetings(dbMeetings);
return result;
}
}
而TranslateMeetings
方法:
internal static IEnumerable<Meeting> TranslateMeetings(IEnumerable<DBMeeting> dbMeetings)
{
foreach (var dbMeeting in dbMeetings)
{
yield return TranslateMeeting(dbMeeting);
}
}
internal static Meeting TranslateMeeting(DBMeeting dbMeeting)
{
return new Meeting
{
Id = dbMeeting.ID,
Name = dbMeeting.Name,
Description = dbMeeting.Description
// other properties
};
}
现在在客户端,当我调用GetMeetings()
并尝试枚举列表时,我得到一个InvalidOperationException
说:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
我特别不想在服务器端运行.ToList()
,因为我希望枚举在客户端发生。但是,在我的TranslateMeetings()
方法中,我正在创建新的会议对象,这些对象不会以任何方式映射到我的模型。那么,为什么它仍然需要上下文存在呢?为什么 EF 试图跟踪未映射的 (Meeting
( 对象?
问题是实体框架使用延迟计算。它不会尝试将对象从数据库中取出,除非绝对必要。
此外,通过在TranslateMeetings
方法中使用yield return
,您将在那里使用延迟评估。该方法中的代码在您实际迭代之前不会运行。
因此,当您返回result
时,尚未对数据库进行调用。稍后,当您尝试迭代result
时,TranslateMeetings
方法将尝试迭代dbMeetings
对象。这将触发实体框架执行 SQL 并尝试填充dbMeetings
。但到那时,上下文已被释放,因此调用失败。
我知道你说你不想跑.ToList((,但这几乎是你必须做的。不能将评估推迟到上下文被释放之后!客户端(我假设这是一个 API?(不能是执行实体框架的客户端。它只是不是那样工作的。客户端需要接收填充的对象。
这是因为一旦到达using
范围的末尾,您就已释放了 EF 上下文:
using(var context = new MyDataContext())
{
var dbMeetings = context.GetMeetings(null, null);
var result = ComplexToEntityTranslator.TranslateMeetings(dbMeetings);
return result;
}
稍后,当您枚举IEnumerable
时,您将尝试访问实体。