2014-09-08 3 views
1

Я использую Entity Framework 6 для запроса некоторых объектов с помощью хранимой процедуры, которая возвращает объект Complex. Прежде чем возвращать эти объекты клиенту, я «переводим» их в объекты, специфичные для клиента.«Экземпляр объекта ObjectContext был удален» для объектов, отличных от EF.

На стороне сервера, я следующий код, чтобы получить сложные объекты типа 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)?

+1

Вы не говорите нам, что возвращает 'context.GetMeetings', но независимо от того, я не понимаю ваш оператор:« Я специально не хочу запускать '.ToList()' на стороне сервера, потому что я хотите, чтобы перечисление происходило на стороне клиента ». Что именно вы надеетесь достичь? Клиент на сервер не будет участвовать в ленивом использовании оператора 'yield', поскольку он перечисляет. Как это возможно реализовать? Так что да, вызовите '.ToList()' - вот что вам следует делать, и реализовать последовательность на месте перед удалением - это ваш единственный вариант. –

ответ

4

Проблема заключается в том, что Entity Framework использует отложенную оценку. Он не будет пытаться получить объекты из базы данных, пока это не произойдет.

В дополнение, используя yield return в вашем методе TranslateMeetings, вы используете отложенную оценку там. Код в этом методе не запускается до тех пор, пока вы на самом деле не перейдете к нему.

Таким образом, к моменту возврата result звонок еще не был доставлен в базу данных. Позже, когда вы попытаетесь выполнить итерацию по result, метод TranslateMeetings попытается выполнить итерацию по объекту dbMeetings. Это вызовет структуру сущности для выполнения SQL и попытается заполнить dbMeetings. Но к тому времени контекст был удален, поэтому вызов терпит неудачу.

Я знаю, что вы сказали, что не хотите запускать .ToList(), но это в значительной степени то, что вам нужно делать. Вы не можете отложить оценку до тех пор, пока контекст не будет удален! Клиент (я предполагаю, что это API?) Не может быть тем, кто должен выполнить Entity Framework. Это просто не работает. Клиент должен получать населенные объекты.

+0

'Код в этом методе не запускается до тех пор, пока вы на самом деле не перейдете к нему.' Там. Это то, что я искал! – user2872534

0

Ну это потому, что вы расположены контекст EF один раз в конце using объема достигается:

using(var context = new MyDataContext()) 
{ 
    var dbMeetings = context.GetMeetings(null, null); 
    var result = ComplexToEntityTranslator.TranslateMeetings(dbMeetings); 
    return result; 
} 

И вы пытаетесь получить доступ к субъектам позже, когда вы перечислить IEnumerable ,

Смежные вопросы