2011-02-07 54 views
0

這對我來說有點難以用書面的方式解釋,我很欣賞你們花時間閱讀這個長長的問題。我打開不使用LINQ查詢來解決這個問題,只是做一些類型的循環或遞歸,如果更好的工作。權限系統3個層次結構的LINQ查詢

我正在使用基於NETSqlAzMan的權限/授權系統。
這些是主要的概念:

  • 權限是可以授權給定的兩個「安全對象」的權利。
  • 「安全」是可以作出兩個授權(Think用戶或用戶組在這裏)的對象,以及它們可以作爲的對象(認爲文件或文檔)。例如:User1和File1都是「安全」,User1可以被授權編輯File1。
  • 「安全」可以有父母和子女的「安全」。
  • 「權限」可以擁有父級和/或子級權限。

這是如何工作的更具體的例子。

安全對象:

- Administrators 
    - Tom 
    - Mike 
- Editors 
    - John 
    - Lisa 
- Documents 
    - Document1 
    - Document2 

權限:

  • Edit_Document
    • Edit_Title
    • Edit_Body
    • Change_BGColor

上述數據存儲在2個表中,安全性和權限有2箇中間表,GroupMembership(安全層次結構)和PermissionRelationship(權限層次結構)。

還有一個稱爲Authorization的表,它包含由一個Securable組成的「AuthorizedID」,一個Securable作爲「SecurableID」,一個Permission作爲「PermissionID」以及一個Enum,它們可以是Inherit 0),允許(1)或拒絕(2)。

我有LINQ2SQL實體設置爲所有表以及一個函數返回給定的Securable的祖先和一個返回給定的權限的祖先的所有。

我很努力地確定一個查詢,可以正確檢查每個權限的所有3個層次結構,以確定對於給定的AuthorizedID和SecurableID設置授權的有效權限和最近的授權ID級別。

例如: 如果管理員正在爲「Edit_Document」權限授予「允許」的「文檔」,然後爲「管理員」和「文檔」 SecurableiD給定AuthorizedID查詢應該返回:

  • AuthorizedID:管理員SecurableID:文檔允許許可:Edit_Document
  • AuthorizedID:管理員SecurableID:文檔允許許可:Edit_Title
  • AuthorizedID:管理員SecurableID:文檔允許許可:Edit_Body
  • AuthorizedID:管理員SecurableID:文檔允許許可:Change_BGColor

如果另外的授權被增加了對「文檔1」,「邁克」與拒絕「Change_BGColor」(拒絕覆蓋任何允許在鏈進一步向下),則查詢的 「邁克」 的AuthorizedID和 「文檔1」 的SecurableID的結果將返回:

  • AuthorizedID:管理員SecurableID:文件允許權限:Edit_Document
  • AuthorizedID:管理員SecurableID:文件允許權限:Edit_Title
  • AuthorizedID:管理員SecurableID:文件允許權限:Edit_Body
  • AuthorizedID:邁克SecurableID:文檔1拒絕權限:Change_BGColor

這是我迄今爲止,處理AuthorizedID的層次和SecurableID罰款,但沒有按」請適當考慮權限的層次結構。我不確定如何將權限層次結構考慮在內,以便如果某個權限的祖先被設置爲拒絕,那麼子權限也顯示拒絕,並且結果包括設置了拒絕的AuthorizedID和SecurableID。

public List<LocalPermission> GetSecurablesLocalPermissions(Guid authorizedID, Guid securableID) 
    { 
     var localAuthorization = (from eff in 
             (from p in dc.Permissions 
             let a = (from sa in dc.AllSecurablesAuthorizations(authorizedID) 
               where sa.PermissionID == p.PermissionID 
               group sa by sa.PermissionID into g 
               select g.OrderBy(x => x.Lvl).OrderByDescending(x => x.AuthorizationBits).First()).FirstOrDefault() 
             select new 
             { 
              PermissionID = p.PermissionID, 
              PermissionName = p.PermissionName, 
              AuthorizationBits = a.AuthorizationBits ?? 0, 
              SecurableID = a.SecurableID ?? Guid.Empty, 
              SecurableName = a.SecurableName, 
              AuthorizedName = a.AuthorizedName, 
              AuthorizedID = a.AuthorizedID ?? Guid.Empty 
             }) 
            join l in 
             (from p in dc.Permissions 
             join la in dc.Authorizations 
              on p.PermissionID equals la.PermissionID into laJoin 
             from localJoin in laJoin.Where(x => (x.SecurableID == securableID /*|| localJoin.SecurableID == Guid.Empty*/) && (x.AuthorizedID == authorizedID /*|| localJoin.AuthorizedID == Guid.Empty*/)).DefaultIfEmpty() 
             select new 
                { 
                 PermissionID = p.PermissionID, 
                 PermissionName = p.PermissionName, 
                 AuthorizationBits = localJoin == null ? 0 : localJoin.AuthorizationBits, 
                 SecurableID = localJoin == null ? Guid.Empty : localJoin.SecurableID, 
                 SecurableName = localJoin == null ? null : localJoin.SecurableName, 
                 AuthorizedName = localJoin == null ? null : localJoin.AuthorizedName, 
                 AuthorizedID = localJoin == null ? Guid.Empty : localJoin.AuthorizedID 
                }) on eff.PermissionID equals l.PermissionID 
            select new LocalPermission 
            { 
             PermissionID = l.PermissionID, 
             PermissionName = l.PermissionName, 
             AuthorizationBits = l.AuthorizationBits, 
             SecurableID = securableID, 
             SecurableName = (from s in dc.Securables 
                 where s.SecurableID == securableID 
                 select s).SingleOrDefault().SecurableName, 
             AuthorizedID = authorizedID, 
             AuthorizedName = (from s in dc.Securables 
                 where s.SecurableID == authorizedID 
                 select s).SingleOrDefault().SecurableName, 
             EffectiveAuthorizationBits = eff.AuthorizationBits == 0 ? l.AuthorizationBits : eff.AuthorizationBits 
            }).ToList<LocalPermission>(); 

     return localAuthorization; 
    } 
+0

我的看法:只是因爲LINQ啓用這樣的巨大語句並不意味着你應該使用它們。可讀性規模非常低。 – 2011-02-07 19:20:49

回答

0

這太討厭了。

回答:「這樣如果某個權限的祖先被設置爲拒絕,那麼子權限也會顯示拒絕」這意味着您需要遞歸。數據庫中的父/子關係通常意味着遞歸。 linq不支持遞歸,但本機sql不支持(公用表表達式)。

我的策略是將所有權限放入列表中,然後編寫普通的程序遞歸代碼來回答您的查詢(我沒有完全理解)。在這種情況下,我推薦TDD。希望這有助於讓你走上正軌。