如何在这里摆脱交叉连接?

How to get rid of cross join here?

我有执行缓慢的代码,因为被转换成奇怪的 SQL:

        // Create LINQ query for retrieving objects on which user has permissions to perform supplied action
        var result =

            // Select objects from supplied queryable
            from secureObject in source

            // Create some shorthands for code readablility
            let ownerId = secureObject.AccessControl.OwnerId
            let groupOwner = secureObject.AccessControl.GroupOwner
            let permissions = secureObject.AccessControl.Permissions
            let objectStatus = secureObject.AccessControl.Status

            // Filter out actions that do not apply to this object source
            from ia in this.ImplementedActions
                .Where(ia =>
                    ia.ObjectType == objectType &&
                    ia.ActionType == actionType &&
                    ((ia.Statuses == Status.None) || ((ia.Statuses & objectStatus) != 0))
                )

            // Get action entry for supplied action
            from ac in this.SecureActions.Where(ac => ac.Type == actionType && secureObject != null)

            // Get user matching current principal id
            from u in this.Users.Where(user => user.Name.Equals(userName))

            // Create left outer join for Privileges
            from pr in this.Privileges.Where(pr =>
                pr.ObjectType == objectType
                && pr.Action == actionType
                && (
                    pr.Type == PrivilegeType.Global
                    || (pr.Type == PrivilegeType.Object && pr.RelatedObjectId == secureObject.SecureId)
                    || (pr.Role == RoleType.Self && u.SecureId == secureObject.SecureId && objectType == typeof(User).Name)
                )
            ).DefaultIfEmpty()

            where
                // The action must apply to objects
                ac.AppliesToObject == true
                //ac.AppliesToObject == true

                && (
                // Administrators are always allowed to do everything
                    ((u.Groups & Groups.Administrators) == Groups.Administrators)

                    // Read permissions in the bit field 
                    || (actionType == ActionType.Read && (

                        // The OtherRead access permission bit is on
                        ((permissions & AccessPermissions.OtherRead) != 0)

                        // The OwnerRead access permission bit is on, and the member is the owner
                        || ((permissions & AccessPermissions.OwnerRead) != 0 && ownerId == u.SecureId)

                        // The GroupRead permission bit is on, and the member is in the group
                        || ((permissions & AccessPermissions.GroupRead) != 0 && (groupOwner & u.Groups) != 0))
                    )

                    // Write permissions in the bit field                        
                    || (actionType == ActionType.Write && (

                        // The OtherWrite access permission bit is on
                        ((permissions & AccessPermissions.OtherWrite) != 0)

                        // The OwnerWrite acccess permission bit is on, and the member is the owner
                        || ((permissions & AccessPermissions.OwnerWrite) != 0 && ownerId == u.SecureId)

                        // The GroupWrite permission bit is on, and the member is in the group
                        || ((permissions & AccessPermissions.GroupWrite) != 0 && (groupOwner & u.Groups) != 0))
                    )


                    // Delete permissions in the bit field       
                    || (actionType == ActionType.Delete && (

                        // The OtherDelete access permission bit is on
                        ((permissions & AccessPermissions.OtherDelete) != 0)

                        // The OwnerDelete access permission bit is on, and the member is the owner
                        || ((permissions & AccessPermissions.OwnerDelete) != 0 && ownerId == u.SecureId)

                        // The GroupDelete access permission bit is on, and the member is in the group
                        || ((permissions & AccessPermissions.GroupDelete) != 0 && (groupOwner & u.Groups) != 0))
                    )

                    // User privileges
                    || (pr.Role == RoleType.User && pr.Who == u.SecureId)

                    // Owner privileges
                    || (pr.Role == RoleType.Owner && ownerId == u.SecureId)

                    // OwnerGroups privileges
                    || (pr.Role == RoleType.OwnerGroup && ((groupOwner & u.Groups) != 0))

                    // Group privileges
                    || (pr.Role == RoleType.Group && ((pr.Who & (int)u.Groups) == pr.Who))
                )

                //self privileges
                || (pr.Role == RoleType.Self)

            select secureObject;

在这里,ImplementedActions 和 Privileges 相应地转换为 INNER / LEFT JOINs,但是 SecureActions 和 Users 只是 CROSS JOINed (?!)

我很惊讶,因为从条件来看,应该只选择了一个用户,例如,所以我预计会是这样的:

INNER JOIN "XXX"."USER" "ExtentY" ON ("ExtentY"."USER_NAME" = :p__linq__Z)

而不是

CROSS JOIN "XXX"."USER"

你能告诉我,这里有什么问题吗?

匿名对象救了我(然而,性能仍然不佳,但这已经是数据库管理员的问题,因为他们说 Oracle 计划不是最优的):

            // Select objects from supplied queryable
            from secureObject in source
            // Get user matching current principal id
            join u in this.Users on new { key = userName } equals new { key = u.Name }
            // Get action entry for supplied action
            join ac in this.SecureActions on new { key1 = actionType, key2 = true } equals new { key1 = ac.Type, key2 = ac.AppliesToObject }