0

Я работаю над приложением .NET 4, C#, Entity Framework 4, SQL Server 2008.Как я могу реорганизовать этот метод IQueryable <T>?

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

Теперь в моем репозитории я пытаюсь определить контракт интерфейса, который имеет только один метод Find(). Для этого я создал абстрактный класс под названием «Местоположение», для которого все объекты 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().

По сути, мне нужен метод репозитория, который возвращает все страны/города/государства и т. Д. (Как 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(); 
.... 

Тьфу!

Это то, что мой репозиторий договора в данный момент выглядит (и я хочу, чтобы сохранить его таким образом):

IQueryable<Location> Find(); 

Таким образом, любые лучшие идеи, чем имеющие все те СОЮЗА? Метод расширения IQueryable<T>, который может динамически соединяться с несколькими IQueryable?

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

Оцените справку.

+0

Я не буду говорить, что ваш дизайн «неправильный» ... давайте просто скажем: «Я не понимаю». Это, как говорится, похоже, что вы хотите выполнять поиск, например: все улицы в определенном городе; все почтовые индексы касаются определенной улицы; все города и районы в определенном графстве; все улицы в определенном районе; и т. д. Это близко? –

+0

@Neil T - место сверху. Я хочу, чтобы иметь возможность искать любое «местоположение» (город/страна/штат) на основе предикатов. Я не хочу иметь в репозитории с IQueryable FindCities(), IQueryable FindStates() и т. Д. Мне нужен единственный метод Find(), который способен возвращать коллекцию любого типа местоположения. – RPM1984

+0

Является ли «Местоположение» также классом сущности? Если да, то почему вы не можете просто извлечь все экземпляры «Местоположение» из репозитория? – Jacob

ответ

1

Я предполагаю, что один и тот же логический объект не будет существовать в двух отдельных таблицах (например, «город» не является «состоянием»). В этом случае вам лучше использовать 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()); 
} 
+0

@Yep, вот что я искал. Тем не менее, я теперь переосмыслил свой дизайн (из-за ответа Джейкоба). Это, как говорится, вероятно, правильный ответ, основанный на моем первоначальном вопросе. Благодарю. – RPM1984

1

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

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

+0

согласны (частично). Первоначально я создал таблицу Location и имел наследование. Но дело в том, что «общие поля» в объекте «Место» - это настраиваемые свойства, созданные на основе бизнес-логики. Т.е. - URL-адреса, форматированный адрес и т. Д. Поэтому я бы только создал таблицу для удовлетворения требований EDM - должен быть наоборот (IMO). Цените ответ, хотя - переосмыслите мой дизайн. – RPM1984

+0

Позвольте мне спросить его так. Допустим, у меня нет таблицы местоположений. Как я могу вернуть смешанную сумку City, State, Street в одной коллекции из репозитория? т.е. var heapsOfStuff = repository.Find(). Где (s => Name.Contains ("new york")). «Имя» может быть абстрактным членом, общим для всех типов. Знаешь что я имею ввиду? Я хочу, чтобы пользовательский интерфейс мог уйти - «заведите меня во все местоположения, у которых есть« новый йорк »в названии». Эти места могут быть любыми (улицы, цитаты и т. Д.). Как я могу это сделать? – RPM1984

+0

Я бы пошел с ответом, который вы приняли, если не было базы 'Местоположение'. – Jacob

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