Могу ли я реорганизовать переменную диапазона в операторе linq? - PullRequest
1 голос
/ 10 февраля 2010

У меня есть проект Entity Framework 3.5, в котором я использую наследование TPH. Два моих конкретных типа находятся в своем собственном классе DAO и содержат селектор, который проецирует класс сущности в DTO. Тем не менее, оба этих конкретных класса имеют сходные отношения с другой таблицей, которую я четко использую для выражения. У меня вопрос, могу ли я каким-то образом изменить этот оператор let, потому что, создавая более унаследованные конкретные классы, я чувствую, что нарушаю DRY.

StudentDAO.cs:

var myDTO = from x in context.Students
let address = (from a in x.addresses where a.active == true select a).FirstOrDefault()
select new StudentDTO { id = x.id, studentname = x.studentname, address = a.address};

ProfessorDAO.cs:

var myDTO = from x in context.Professors
let address = (from a in x.addresses where a.active == true select a).FirstOrDefault()
select new ProfessorDTO { id = x.id, professorname = x.studentname, address = a.address};

так есть ли способ я могу реорганизовать адрес из обоих этих запросов?

1 Ответ

2 голосов
/ 10 февраля 2010

Краткий ответ: Боюсь, вы мало что можете легко сделать. Проблема в том, что вам нужно параметризовать запрос. Однако запрос должен быть представлен в виде дерева выражений (чтобы его можно было преобразовать в SQL или в любой другой формат EF). К сожалению, в C # нет элегантных способов составления деревьев выражений.

Длинный ответ: Некоторое время назад я написал статью на C #, в которой объясняется , как составлять запросы (используя некоторые приемы) - вы можете взять дерево выражений и объединить его в параметризованный запрос. Таким образом, в принципе вы можете использовать методы из этой статьи, чтобы создать метод, который принимает изменяющиеся части дерева выражений, а затем составляет запрос.

Я буду использовать типы, используемые в LINQ to SQL, потому что я более знаком с ним, но я считаю, что принцип должен быть таким же:

IQueryable<R> GetInfo<T>(IQueryable<T> source, // e.g. context.Students
  Expression<Func<T, IQueryable<Address>>> getAddr, // x => x.adresses
  Expression<Func<T, Address, R>> getRes // (x, a) => new StudentDTO { ... }
  return
    from x in source.AsExpandable()
    let address = (from a in getAddr(x).Expand() where a.active == true 
                   select a).FirstOrDefault() 
    select getRes(x, a).Expand();
}

// The use would look like this
var res = GetInfo(context.Professors, x => x.addresses, (x, a) => new 
  ProfessorDTO { id = x.id, professorname = x.studentname, address = a.address }); 

Итак, в итоге, C # и LINQ не предоставляют никакой встроенной поддержки, которая упростила бы процесс. Однако с некоторыми усилиями вы можете написать запрос, параметризованный некоторыми частями дерева выражений. В вашем случае это делает код немного короче и менее повторяющимся, но делает его намного более сложным (и вам также нужно использовать библиотеку, подобную той, на которую я ссылался, которая обеспечивает AsExpandable и Expand).

В этом случае я боюсь, что это не стоит усилий. Но было бы неплохо, если бы C # v (Next) ^ x предоставил более элегантную поддержку для таких вещей: -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...