2013-08-05 39 views
2

我正在创建一个报告,根据用户定义的过滤标准列出数据库中的人员。因此,例如,我可以通过姓名,年龄等如何为SQL交叉连接编写Linq表达式?

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

现在的过滤标准之一是要表明谁没有过自己的免疫接种要求的人进行筛选。我有ImmunizationPersonImmunization(在PersonID, ImmunizationID上有唯一索引)的表格。如果有人遗漏了任何记录,或者他们收到的剂量数量低于要求,则应该包括这些记录,否则应该包括这些记录。

如果我写一个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; 
为了让我的where子句中的这一部分

现在,我需要这个使用Expression谓词来表达:

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

我遇到的第一个问题是如何将免疫接种到表达式中。然后,一旦我有了它,我怀疑找到不合规的人可能会更直接,但如果你可以在你的答案中包括这一点,我会非常感激!

编辑:我已经被要求解释为什么我如此设置使用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为了防止混淆,我从实际的代码中删除了一些内容;请接受,因为我需要'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 }; 

编辑:为了使其适合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绝对不是。这会失去交叉连接和左连接。另外,我需要它作为'Expression >;查询语法不起作用。 –

+0

具体而言,为什么查询语法不起作用? –

+0

@Shaul表达式在逻辑上是相同的,你永远不需要*交叉连接和左连接,数据库将选择最优的执行计划。 – 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语法,但我特别希望它是一个'Expression >。这个问题从我的实际代码中解脱出来以防止混淆;请仅接受查询语法不足以满足我的目的。 –