Skip to content

Incorrect HQL Generation for GroupBy with CUBE #3659

@Annaklychev

Description

@Annaklychev

Problem Description
When using .GroupBy(q => new { q.Url, q.ProfileId }.Cube()), the ORM generates an incorrect SQL query. It is expected that GROUP BY CUBE(...) will include both fields (Url and ProfileId), but in the generated query, only the first field (Url) is included.

Example Code (LINQ Query)

var query = _repositoryRequest.Query()
    .GroupBy(q => new { q.Url, q.ProfileId }.Cube())
    .Select(c => new { c.Key.Url, c.Key.ProfileId });

Generated SQL (Incorrect)

GROUP BY CUBE(request0_.url)

Expected SQL (Correct)

GROUP BY CUBE(request0_.url, request0_.profile_id)

CubeHqlGenerator

public class CubeHqlGenerator : BaseHqlGeneratorForMethod
{
    public CubeHqlGenerator()
    {
        SupportedMethods = new[]
        {
            typeof(GroupByExtensions).GetMethod(nameof(GroupByExtensions.Cube))
        };
    }

    public override HqlTreeNode BuildHql(
        MethodInfo method,
        Expression target,
        ReadOnlyCollection<Expression> arguments,
        HqlTreeBuilder treeBuilder,
        IHqlExpressionVisitor visitor)
    {
        if (arguments[0] is NewExpression newExpression)
        {
            var visitedExpressions = newExpression.Arguments
                .Select(expr => visitor.Visit(expr).AsExpression())
                .ToArray();

            if (IsCalledInGroupBy())
            {
                return treeBuilder.MethodCall("CUBE", visitedExpressions);
            }
            else
            {
                return visitedExpressions[0];
            }
        }
        else
        {
            var sourceExpression = visitor.Visit(arguments[0]).AsExpression();

            if (IsCalledInGroupBy())
            {
                return treeBuilder.MethodCall("CUBE", sourceExpression);
            }
            else
            {
                return sourceExpression;
            }
        }
    }
    private bool IsCalledInGroupBy()
    {
        var stackTrace = new StackTrace();
        foreach (var frame in stackTrace.GetFrames())
        {
            var method = frame.GetMethod();
            if (method.Name.Contains("Select"))
                return false;
            if (method.DeclaringType?.ToString().Contains("ProcessGroupBy")??false)
                return true;
        }
        return false;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions