ASP.Net Entity Framework, objectcontext error

Я создаю 4-слойное веб-приложение ASP.Net. Слои:

  • Уровень данных
  • Уровень сущности
  • Бизнес-уровень
  • Уровень пользовательского интерфейса

Уровень сущности имеет мои классы моделей данных и построен из моей модели данных сущности (файл edmx) в datalayer с использованием шаблонов T4 (POCO). Уровень сущности ссылается во всех остальных слоях.

В моем слое данных есть класс, называемый SourceKeyRepository, который имеет такую ​​функцию:

public IEnumerable<SourceKey> Get(SourceKey sk)
{
    using (dmc = new DataModelContainer())
    {
        var query = from SourceKey in dmc.SourceKeys
                    select SourceKey;

        if (sk.sourceKey1 != null)
        {
            query = from SourceKey in query
                    where SourceKey.sourceKey1 == sk.sourceKey1
                    select SourceKey;
        }

        return query;
    }
}

Lazy loading отключен, так как я не хочу, чтобы мои запросы выполнялись в других слоях этого приложения. При попытке получить доступ к информации в слое пользовательского интерфейса я получаю следующую ошибку:

Экземпляр ObjectContext был и больше не могут использоваться для операции, требующие подключения.

Я уверен, что это связано с тем, что мой DataModelContainer "dmc" был удален. Как я могу вернуть этот объект IEnumerable из моего слоя данных, чтобы он не полагался на ObjectContext, но только на DataModel?

Есть ли способ ограничить ленивую загрузку только в слое данных?

Ответ 1

query ленив, поэтому данные не удаляются из базы данных, пока вы не перечислите ее.

Если вы выполните:

return query.ToList();

вы принудительно выполняете запрос и избегаете проблемы.

Вы получаете сообщение об ошибке, потому что, когда вызывающий абонент перечисляет коллекцию, ObjectContext (dmc) уже размещен благодаря вашему предложению using (что хорошо - рано или поздно располагайте ресурсы, связанные с базой данных)

Изменить

В исходном посте я использовал AsEnumerable(), который, как я думал, был прав, пока я не попытался использовать его в этой конкретной ситуации сам. AsEnumerable() делает только преобразование типа компиляции - он не перечисляет. Чтобы заставить запрос перечислить, он должен быть сохранен в List или другой коллекции.

Ответ 2

Вы можете вызвать некоторый метод для объекта query, например

return query.AsEnumerable();

Это должно убедиться, что вы выполняете запрос, поэтому убедитесь, что вам больше не нужен контекст объекта.

Ответ 3

Не используйте

return query.AsEnumerable();

использование

return query.ToArray();

прежде чем удалять контекст.

Возврат AsEnumerable не будет выполнять foreach до тех пор, пока объект не будет указан. Преобразование его в массив гарантирует, что foreach будет выполняться до того, как ваш объект будет удален. Вы можете разместить свой контекст в блоке использования (что-то, что вы должны сделать).

Ответ 4

По-моему, этот сценарий не имеет отношения к AsEnumerable() или AsQueryable(). Попробуйте это;

 public IEnumerable<SourceKey> Get(SourceKey sk, DataModelContainer dmc) {    

    var query = from SourceKey in dmc.SourceKeys
                select SourceKey;

    if (sk.sourceKey1 != null)
    {
        query = from SourceKey in query
                where SourceKey.sourceKey1 == sk.sourceKey1
                select SourceKey;
    }

    return query;

}

И вы должны получить это свойство с помощью

using (dmc = new DataModelContainer()) {
 // GET
}