2013-08-05 38 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 >。這個問題從我的實際代碼中解脫出來以防止混淆;請僅接受查詢語法不足以滿足我的目的。 –