2011-02-07 79 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。希望这有助于让你走上正轨。