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
}