2014-01-14 71 views
3

簡體域名:QueryOver集合包含所有值

public class MasterDocument { 
    Guid ID; 
    Program StorageCompartment; 
    ISet<DocumentCompartment> Compartments; 
} 
public class Program { 
    int ID; 
    string GroupName; 
} 
public class DocumentCompartment { 
    int ID; 
    Program AssociatedCompartment; 
    MasterDocument AssociatedDocument; 
} 
public class Document { 
    Guid ID; 
    MasterDocument MasterDocument; 
    //Many more properties 
} 

我知道這有點令人費解,但存在這樣的,因爲我們已經通過把某些記錄(如文件)爲不同的處理安全問題的模式數據庫對應於它們所屬的程序/艙(可互換術語)。 MasterDocument,Program和DocumentCompartment的表位於「主」數據庫中,其中包含所有隔離專區的信息,而幾個不同的數據庫則分別包含自己的Documents表。無論如何,在這個問題上:

我想構建一個查詢,我傳遞了一個組名列表,並且我只想要那些沒有包含在該組名列表中的關聯隔離的文檔。

作爲一個例子:
文檔1與隔室相關聯的P1
文檔2與P2,P3相關聯,並且P7
文檔3與P1相關聯,並且P3
我想要查詢針對組:P1,P3, P4,P7(這些是我獲得許可的組)

我應該找回Doc1和Doc3,因爲我沒有P2權限,Doc2需要這個權限。我可以這樣使用LINQ提供程序使用下面的查詢做:

string[] groups = new[] { "P1", "P3", "P4", "P7" }; 
return Session.Query<Document>().Where(doc => doc.MasterDocument.Compartments.All(comp => groups.Contains(comp.AssociatedCompartment.GroupName)); 

(同樣在上面記:如果我嘗試封裝在文檔類是邏輯和方法傳遞給「去哪兒」方法,例如返回Session.Query()。其中​​(doc => doc.CanAccess(groups)),然後我得到一個System.NotSupportedException。我有點理解爲什麼,但如果有解決方法,這將是非常好的。

產生的生成的SQL是這樣的:

exec sp_executesql 
N'select 
doc.DocumentGuid as guid 
from Documents doc 
where not (exists 
(select comp.DocumentCompartmentID 
from Master.MasterDocuments master, 
     Master.DocumentCompartments comp, 
     Master.Programs prog 
where doc.DocumentGuid=master.DocumentGuid and 
     master.DocumentGuid=comp.DocumentGuid and 
     comp.CompartmentID=prog.ProgramID and 
     not (prog.ADGroupName in ('P1', 'P3', 'P4', 'P7')) 
))', 

我現在TR要弄清楚如何使用NHibernate QueryOver語法來完成相同的查詢。不幸的是,我沒有足夠的知識或經驗知道如何編寫它。任何幫助,將不勝感激!

回答

1

我相信你想是這樣的:

IList<Guid> results = Session.QueryOver<Document>(() => documentAlias) 
    .WithSubquery.WhereNotExists(
     QueryOver.Of<MasterDocument>() 
       .Where(md => md.ID == documentAlias.MasterDocument.ID) // Not sure about this 
      .JoinQueryOver(md => md.Compartments) 
      .JoinQueryOver(cmp => cmp.AssociatedCompartment) 
       .WhereNot(acmp => acmp.GroupName.IsIn(new[] { "P1", "P3", "P4", "P7" }))) 
    .Select(doc => doc.ID) 
    .List<Guid>(); 

我不知道,如果MasterDocument.IDDocument.MasterDocument.ID之間的比較是正確的,我發表過評論,但這應該讓你在正確的方向開始。

的幾個注意事項:

  • 一般情況下,你不能使用LINQ的語法與QueryOver。他們看起來很相似,但他們是不同的查詢技術。
  • 有關QueryOver的基本介紹,請查看nhibernate.info上的this guide。不幸的是,這與你在官方文檔中可以得到的一樣好。
  • 這假設你根據你所呈現的類的幾個關於映射的東西。
+0

那麼,*似乎*工作。我沒有真正創建任何單元測試,以確保它做我想做的事情,但調用我的查詢方法的單元測試至少現在不會在NHibernate代碼中引發異常。 –

+0

Btw,你是否有可能在Document類中封裝LINQ邏輯有任何評論,所以我可以這樣調用它:Session.Query()。Where(doc => doc.CanAccess(groups))?我真正想要做的是攔截我們的查詢,檢查T是否是特定類型(例如ISecurable,它定義了bool CanAccess(...)),並插入表達式以僅當我可以訪問'它。如上所述,內聯邏輯起作用,但試圖在方法內調用該邏輯不會。 –

+0

通常,您不能從QueryOver查詢中調用實體的方法。將QueryOver視爲直接轉換爲SQL。因此,'CanAccess'在SQL查詢中沒有意義。你將不得不水合實體和*然後*調用該方法。 –

相關問題