Как обернуть EF 4.1 DbContext в хранилище? - PullRequest
0 голосов
/ 27 мая 2011

All

У меня есть требование скрыть мою реализацию EF за репозиторием. Мой простой вопрос: есть ли способ выполнить «поиск» как для DbSet, так и для DbSet.Local без необходимости иметь дело с ними обоими.

Например - у меня есть стандартная реализация репозитория с Add / Update / Remove / FindById. Я нарушаю общий шаблон, добавляя метод FindByName (только для демонстрационных целей :). Это дает мне следующий код:

Клиентское приложение:

ProductCategoryRepository categoryRepository = new ProductCategoryRepository();
categoryRepository.Add(new ProductCategory { Name = "N" });
var category1 = categoryRepository.FindByName("N"); 

Осуществление

public ProductCategory FindByName(string s)
{
    // Assume name is unique for demo
    return _legoContext.Categories.Where(c => c.Name == s).SingleOrDefault();
}

В этом примере категория 1 равна нулю.

Однако, если я реализую метод FindByName как:

public ProductCategory FindByName(string s)
{
    var t = _legoContext.Categories.Local.Where(c => c.Name == s).SingleOrDefault();
    if (t == null)
    {
        t = _legoContext.Categories.Where(c => c.Name == s).SingleOrDefault();
    }
    return t;
}

В этом случае я получаю то, что ожидаю, когда запрашиваю как новую запись, так и ту, которая есть только в базе данных. Но это вызывает некоторые проблемы, из-за которых я запутался:

1) Я бы предположил (как пользователь хранилища), что cat2 ниже не найден. Но он найден, и большая часть заключается в том, что cat2.Name является "Goober".

ProductCategoryRepository categoryRepository = new ProductCategoryRepository();
var cat = categoryRepository.FindByName("Technic");
cat.Name = "Goober";
var cat2 = categoryRepository.FindByName("Technic");

2) Я хотел бы вернуть общий IQueryable из моего хранилища.

Просто кажется, что нужно много работы, чтобы обернуть вызовы DbSet в хранилище. Как правило, это означает, что я что-то напортачил. Буду признателен за понимание.

1 Ответ

0 голосов
/ 30 мая 2011

С более старыми версиями EF у вас были очень сложные ситуации, которые могли возникнуть довольно быстро из-за необходимых ссылок. В этой версии я бы рекомендовал не выставлять IQueryable, а ICollections или ILists. Это будет содержать EF в вашем хранилище и создаст хорошее разделение.

Редактировать : более того, отправляя обратно ICollection IEnumerable или IList, вы ограничиваете и контролируете запросы, отправляемые в базу данных. Это также позволит вам более точно настроить и поддерживать систему. Предоставляя IQueriable, вы подвергаете себя побочным эффектам, которые возникают, когда люди добавляют в запрос больше .Take () или .Where ... .SelectMany, EF увидит эти добавления и сгенерирует sql для отражения этих неконтролируемых запросов. Неограниченное количество запросов может привести к выполнению запросов из пользовательского интерфейса, что в долгосрочной перспективе усложнит тесты и проблемы с обслуживанием.

, поскольку цель шаблона репозитория - иметь возможность менять их по желанию. детали DbSets должны быть полностью скрыты.

Я думаю, что вы на правильном пути. Единственное, что я, вероятно, спрашиваю себя:

Длительный ли контекст? если нет, то не беспокойтесь о запросе Local. Объект, который был вставлен / удален, должен быть доступен только после его завершения.

Если это долгоживущий контекст, и вам нужен доступ к удаленным и вставленным объектам, тогда запрос в Local является хорошей идеей, но, как вы указали, в какой-то момент вы можете столкнуться с трудностями.

...