我使用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
)对象?
答案 0 :(得分:4)
问题是实体框架使用延迟评估。它绝不会尝试将对象从数据库中取出。
另外,通过在yield return
方法中使用TranslateMeetings
,您可以在那里使用延迟评估。在您实际迭代它之前,该方法中的代码不会运行。
因此,当您返回result
时,仍未对数据库进行调用。稍后,当您尝试迭代result
时,TranslateMeetings
方法将尝试迭代dbMeetings
对象。这将触发实体框架执行SQL并尝试填充dbMeetings
。但到那时上下文已被处理掉,所以呼叫失败了。
我知道你说你不想运行.ToList(),但这就是你必须做的事情。在上下文处理完毕之前,您无法推迟评估!客户端(我假设这是一个API?)不能是执行实体框架的客户端。它只是不起作用。客户端需要接收填充的对象。
答案 1 :(得分:0)
那是因为您在达到using
范围结束时已经处理了EF上下文:
using(var context = new MyDataContext())
{
var dbMeetings = context.GetMeetings(null, null);
var result = ComplexToEntityTranslator.TranslateMeetings(dbMeetings);
return result;
}
当您枚举IEnumerable
时,您正试图访问以后的实体。