" ObjectContext实例已被处理"对于非EF实体

时间:2014-09-08 16:04:29

标签: c# entity-framework entity-framework-6 objectcontext

我使用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)对象?

2 个答案:

答案 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时,您正试图访问以后的实体