简化过于复杂的LINQ查询 - 查询

时间:2010-10-09 20:09:32

标签: c# linq refactoring

public partial class MembershipModule : BaseEntity<MembershipModule>
{
    /// <summary>
    /// Returns wheter a module is accessible
    /// </summary>
    public static bool IsAccessible(MembershipModule module)
    {
        // In absence of a module, no security applies to the page
        if(module == null)
            return true;

        return module.IsAccessible();
    }

    /// <summary>
    /// Returns whether the module is accessible
    /// </summary>
    /// <returns></returns>
    public bool IsAccessible()
    {
        // Skip unnecessary querying
        if(!MembershipUser.Connected)
            return this.Enabled && this.OfflineAccess;

        Guid accessGuid = MembershipAction.AccessGuid;

        // ModuleActions for this MembershipModule and the Access Action
        IQueryable<MembershipModuleAction> accessMA =
            from ma in LinqUtil.Context.MembershipModuleActions
            where ma.ModuleId.Equals(this.Id) && ma.ActionId.Equals(accessGuid)
            select ma;

        // RolePrivileges that grant access on this MembershipModule for the Current MembershipUser
        IQueryable<bool> accessRP =
            from rp in LinqUtil.Context.MembershipRolePrivileges
            where accessMA.Contains(rp.MembershipModuleAction)
            select rp.MembershipRole.MembershipUsers.Contains(MembershipUser.Current);

        return this.Enabled && (this.OfflineAccess || accessRP.ToList().FirstOrDefault());
    }

    /// <summary>
    /// Returns all accessible modules that can be accessed by the logged user
    /// </summary>
    /// <returns></returns>
    public static IEnumerable<MembershipModule> GetAccesible()
    {
        // Skip unnecessary querying
        if(!MembershipUser.Connected)
            return LinqUtil.Context.MembershipModules.Where(m => m.Enabled && m.OfflineAccess).ToList();

        Guid accessGuid = MembershipAction.AccessGuid;

        // ModuleActions for any MembershipModule with the Access Action
        IQueryable<MembershipModuleAction> accessMA =
            from ma in LinqUtil.Context.MembershipModuleActions
            where LinqUtil.Context.MembershipModules.Any(m => m.Enabled && m.Id.Equals(ma.ModuleId)) && ma.ActionId.Equals(accessGuid)
            select ma;

        // RolePrivileges that grant access on those MembershipModule for the Current MembershipUser
        IQueryable<MembershipRolePrivilege> accessRP =
            from rp in LinqUtil.Context.MembershipRolePrivileges
            where accessMA.Any(ma => rp.MembershipModuleAction.Id.Equals(ma.Id)) && rp.MembershipRole.MembershipUsers.Any(u => u.Id.Equals(MembershipUser.Current.Id))
            select rp;

        // Accessible modules
        var modules =
            from m in LinqUtil.Context.MembershipModules
            where accessMA.Any(ma => ma.MembershipModule.Id.Equals(m.Id)) && accessRP.Any(rp => rp.MembershipModuleAction.ModuleId.Equals(m.Id))
            select m;

        return modules.ToList();
    }

    /// <summary>
    /// Menu Items that can be displayed on the current web page
    /// </summary>
    public static IEnumerable<MembershipModule> GetMenuItems(string uriPrefix)
    {
        IEnumerable<MembershipModule> list = GetAccesible();

        return list.Where(m => m.UriPrefix.Equals(uriPrefix) && m.MenuItem).OrderBy(m => m.Position);
    }
}

这当前有效,但由于某种原因,我不得不认为代码看起来很难看(特别是两个非常相似的静态和实例函数,它们让我获得了可访问的页面

关于如何重构这个看起来更有吸引力的任何想法?

加分问题:

Guid accessGuid = MembershipAction.AccessGuid;

不使用该行,只在我的查询中调用MembershipAction.AccessGuid,我收到一个错误,告诉我一些模糊不清的信息:

  

班级成员   MembershipAction.AccessGuid是   未映射的。

棘手的部分来到这里:在静态GetAccessible()函数中,这不会发生。我可以在查询中添加MembershipAction.AccessGuid,但是在实例IsAccessible()函数中我遇到了这个问题。

记录中,这里是MembershipAction:

public partial class MembershipAction : BaseEntity<MembershipAction>
{
    public const string AccessPrivilege = "Access";

    private static Guid accessGuid = Guid.Empty;
    public static Guid AccessGuid
    {
        get
        {
            if(accessGuid == Guid.Empty)
            {
                IQueryable<Guid> query = from a in LinqUtil.Context.MembershipActions
                                         where a.Name.Equals(AccessPrivilege)
                                         select a.Id;

                accessGuid = query.ToList().FirstOrDefault();
            }

            return accessGuid;
        }
    }
}

2 个答案:

答案 0 :(得分:0)

不是简单的:

public static IEnumerable<MembershipModule> GetAccesible()
{
    // Skip unnecessary querying
    if(!MembershipUser.Connected)
        return LinqUtil.Context.MembershipModules.Where(m => m.Enabled && m.OfflineAccess).ToList();

    // Accessible modules
    var modules =
        from m in LinqUtil.Context.MembershipModules
        where m.IsAccessible()
        select m;

    return modules.ToList();
}

答案 1 :(得分:0)

提到这是个人意见,我们在这里都有:

  1. 放弃在查询中使用lambda表达式。选择一种风格并使用它。
  2. 摆脱where子句中的&符号。你可以从另一行开始用同样的东西。
  3. 不要害怕查询其他查询。如果它更容易理解,没有理由不这样做。编译器会将它们组合成一个查询。
  4. 许多人会指出静态方法经常指向代码气味。为什么需要静态和实例方法?也许课堂上的一些清晰度是有序的。