2013-08-05 2 views
2

Я создаю отчет, чтобы перечислять людей в моей базе данных в соответствии с определяемыми пользователем критериями фильтра. Так, например, я мог фильтровать по имени, возраста и т.д.Как написать выражение Linq для перекрестного соединения SQL?

var people = db.People.AsQueryable(); 
if (filterByName) 
    people = people.Where(p => p.LastName.Contains(nameFilter)); 
if (filterByAge) 
    people = people.Where(p => p.Age == age); 

Теперь, один из критериев фильтра, чтобы показать людям, которые не имели свои необходимые прививки. У меня есть таблицы для Immunization и PersonImmunization (с уникальным индексом на PersonID, ImmunizationID). Если кто-то пропустил какие-либо записи PersonImmunization, или если количество доз, которое они получили, под этим требованием, они должны быть включены, в противном случае нет.

Если бы я писал запрос SQL, это было бы:

select p.* 
from Person p 
cross join Immunization i 
left join PersonImmunization pi 
    on pi.PersonID = p.ID and pi.ImmunizationID = i.ID 
where pi.ID is null or pi.Doses < i.RequiredDoses; 

Теперь для того, чтобы сделать эту часть моего ИНЕК, мне нужно, чтобы выразить это с помощью Expression предиката:

if (filterByImmunizations) { 
    Expression<Func<Person, bool>> nonCompliantImmunization = 
    person => <now what?>; 
    people = people.Where(nonCompliantImmunization); 
} 

Первой проблемой, с которой я столкнулся, является работа с иммунизациями в выражении. Затем, как только у меня есть это, я подозреваю, что поиск несовместимых людей может быть более простым, но если бы вы могли включить это в свой ответ, я был бы очень признателен!

EDIT: Мне было предложено объяснить, почему я так настроен на получение решения, используя Expression<Func<Person, bool>>. Причина в том, что я создал целую общую структуру для написания сложных пользовательских запросов в нескольких разных контекстах. Чтобы дать вам представление о том, что внутри двигателя, вот фрагмент того, что находится внутри моего базового класса:

public abstract class QueryBuilder<T> where T : EntityObject { 

    public static IQueryable<T> FilterQuery(IQueryable<T> query, IEnumerable<QueryConditionLite> filters, bool anyConditionSufficient) { 
    ... 
    } 

    protected Expression<Func<TBase, bool>> GetPredicate(Expression<Func<TBase, double>> expression, IQueryCondition condition) { 
    ... 
    } 
} 

Тогда у меня есть PersonQueryBuilder : QueryBuilder<Person>, и в том, что я хочу, чтобы создать фильтр, который показывает людей, которые не - согласуется с их требованиями к иммунизации. Я думаю, вы согласитесь, что синтаксис запроса просто не собирается его вырезать.

+0

@Nilesh - The que stion отталкивается от моего фактического кода, чтобы предотвратить путаницу; просто примите, что мне нужно выражение 'Expression >', а синтаксис запроса недостаточен для моих целей. –

+1

Измените свой вопрос, чтобы добавить свое обоснование для запрета действительных рабочих решений. –

+1

Почему вы, кажется, думаете, что можете использовать только запрос .Where (...)? – Tory

ответ

2

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

var nonCompiantImmunization = 
    from p in Persons 
    from i in Immunizations 
    let pi = PersonImmunizations.Where(x => 
    x.ImmunizationID == i.ID && x.PersonID == p.ID) 
    where !pi.Any() || pi.Sum(x => x.Doses) < i.RequiredDoses 
    select new { p, i }; 

Edit: Для того, чтобы подогнать его под Expression<Func<Person, bool>> ограничение, я полагаю, вы могли бы перефразировать как:

Expression<Func<Person, bool>> nonCompliantImmunization = 
    person => (
     from i in Immunizations 
     let pi = PersonImmunizations.Where(x => 
     x.ImmunizationID == i.ID && x.PersonID == person.ID) 
     where !pi.Any() || pi.Sum(x => x.Doses) < i.RequiredDoses 
     select true 
    ).Any(); 
+0

-1 Определенно нет. Это теряет как крест-соединение, так и левое соединение. Кроме того, мне нужно это как выражение > '; синтаксис запроса не работает. –

+0

Почему синтаксис запроса не работает? –

+0

@Shaul выражение логически идентично, вы никогда не нуждаетесь * перекрестное соединение и левое соединение, db выберет оптимальный план выполнения. – wendazhou

1

Вы должны уметь писать, например:

var people = db.People.AsQueryable(); 
if(filterByImmunizations) 
{ 
    people = from p in people 
      from i in db.Immunization 
      from pi in db.PersonImmunization.Where(x => 
       x.PersonID == p.ID && x.ImmunizationID == i.ID).DefaultIfEmpty() 
      where pi.ID == null || pi.Doses < i.RequiredDoses 
      select p; 
} 
+0

+1 Это правильный синтаксис Linq, но я хочу, чтобы он был как выражение > '. Вопрос о том, что мой реальный код окунулся, чтобы предотвратить путаницу; просто согласитесь с тем, что синтаксис запроса недостаточен для моих целей. –

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