Как я могу реорганизовать этот метод репозитория IQueryable <T>? - PullRequest
0 голосов
/ 31 августа 2010

Я работаю над приложением .NET 4, C #, Entity Framework 4, SQL Server 2008.

У меня есть 7 таблиц в моей базе данных, каждая из которых представляет определенный уровень местоположения (Страна, Штат, Город, Соседство и т. Д.).

Теперь в моем репозитории я пытаюсь определить интерфейсный контракт, который имеет только один метод Find ().Для этого я создал абстрактный класс «Location», для которого все POCO-местоположения наследуются.

Вот метод, который у меня сейчас есть:

public IQueryable<Location> Find()
{
   return AllCountries()
             .Union(AllStates())
             .Union(AllCounties())
             .Union(AllCities())
             .Union(AllNeigbourhoods())
             .Union(AllZipCodes())
             .Union(AllStreets());
}

Эти встроенные методы (например, AllStates) являются частными методами IQueryable, например:

private IQueryable<Location> AllCountries()
{
   var db = new MyCustomDataContext();
   return db.Countries;
}

Все это прекрасно работает, но мне не нравится внешний вид кода в методе Find ().

По существу,Я хочу метод Repository, который возвращает все страны / города / государства и т. Д. (Как IQuerable<Location>).

Таким образом, мой уровень обслуживания может сделать это:

var countries = repository.Find(somePredicate).OfType<Country>().ToList();

Или вот это:

var countries = repository.Find(somePredicate).OfType<City>().ToList();

Поэтому мне нужно только объявить один метод Find.Вы можете думать о классе Location как о моем «совокупном корне».

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

IQueryable<City> FindCities();
IQueryable<State> FindStates();
IQueryable<Country> FindCountries();
 ....

Yuck!

Вот как выглядит мой контракт на хранилище (и я хочу сохранить его таким):

IQueryable<Location> Find();

Итак, есть ли лучшие идеи, чем иметь все эти профсоюзы?Метод расширения IQueryable<T>, который может динамически связывать несколько IQueryable?

Помните, что у меня также есть Сервисный уровень, который выполняет фильтрацию / сбор проекций (отложенное выполнение).Хранилище должно возвращать «запросы», а не конкретные коллекции.

Оцените помощь.

Ответы [ 2 ]

1 голос
/ 31 августа 2010

Entity Framework позволяет вам сопоставить ваши таблицы с моделью данных, которая использует наследование. Если в вашей базе данных была таблица Location, содержащая все ваши общие поля, и каждый класс подобласти (например, City) имел внешний ключ к этой таблице Location, то при извлечении объектов Location из хранилища вы также должны получать экземпляры унаследованных классов.

Если в Location нет общих полей, то, по-видимому, будет мало пользы от объединенной коллекции.

1 голос
/ 31 августа 2010

Я предполагаю, что одна и та же логическая сущность не будет существовать в двух отдельных таблицах (например, «город» не является «государством»). В этом случае вам лучше использовать Concat вместо Union.

Краткий вспомогательный метод сделает вызов более привлекательным (предупреждение: не проверено):

// (Defined in the static class MyHelpers)
// Concatenate all sequences into one.
public IQueryable<T> ConcatAll<T>(this IQueryable<T> first,
    params IQueryable<T>[] others)
{
  var ret = first;
  foreach (var other in others)
  {
    ret = ret.Concat(other);
  }

  return ret;
}

...

public IQueryable<Location> Find() 
{
  return MyHelpers.ConcatAll(
    AllCountries(),
    AllStates(),
    AllCounties(),
    AllCities(),
    AllNeigbourhoods(),
    AllZipCodes(),
    AllStreets());

  // OR:

  return AllCountries().ConcatAll(
    AllStates(),
    AllCounties(),
    AllCities(),
    AllNeigbourhoods(),
    AllZipCodes(),
    AllStreets());
} 
...