Skip to content

Unable to translate exception on query grouped by LinqExtension field #362

Open
@letarak

Description

@letarak

DO 7.0.3

Fail to execute query that contains > 1 aggregate value by field with link access inside lambda expression

Code sample

using System.Linq.Expressions;
using DoTest;
using Microsoft.Data.SqlClient;
using Xtensive.Orm;
using Xtensive.Orm.Configuration;

internal class Program
{
    private static async Task Main(string[] args)
    {
        try
        {
            DbHelper.ExecuteNonQuery("DROP DATABASE [DO-Tests]");
        }
        catch (Exception)
        {
        }

        DbHelper.ExecuteNonQuery("CREATE DATABASE [DO-Tests]");

        var dc = new DomainConfiguration("sqlserver", new SqlConnectionStringBuilder(DbHelper.ConnectionString()).ToString());

        dc.Sessions.Add(new SessionConfiguration(WellKnown.Sessions.Default) { BatchSize = 25 });
        
        dc.Types.Register(typeof(TestEntity));
        dc.Types.Register(typeof(LinkEntity));

        Expression<Func<TestEntity, decimal?>> lambdaExpression = it => it.Link.Value;
        
        dc.LinqExtensions.Register(typeof(TestEntity).GetProperty(nameof(TestEntity.CalculatedValue)), lambdaExpression);

        dc.UpgradeMode = DomainUpgradeMode.Recreate;

        await using var d = await Domain.BuildAsync(dc);

        await using var s = await d.OpenSessionAsync();
        await using var t = await s.OpenTransactionAsync();
        
        // OK
        _ = s.Query.All<TestEntity>()
            .GroupBy(it => new
            {
                Name = it.Name == null
                    ? string.Empty
                    : it.Name
            }).Select(it => new
            {
                GroupCount = it.Count(),
                it.Key,
                ValueCalculated_Min = it.Min(e => e.CalculatedValue)
            }).Select(it => new
            {
                it.Key.Name,
                Id = Guid.NewGuid(),
                _Count = it.GroupCount,
                it.ValueCalculated_Min
            })
            .ToArray();
        
        // OK
        _ = s.Query.All<TestEntity>()
            .GroupBy(it => new
            {
                Name = it.Name == null
                    ? string.Empty
                    : it.Name
            }).Select(it => new
            {
                GroupCount = it.Count(),
                it.Key,
                ValueCalculated_Min = it.Max(e => e.CalculatedValue)
            }).Select(it => new
            {
                it.Key.Name,
                Id = Guid.NewGuid(),
                _Count = it.GroupCount,
                it.ValueCalculated_Min
            })
            .ToArray();
            
        // OK
        _ = s.Query.All<TestEntity>()
            .GroupBy(it => new
            {
                Name = it.Name == null
                    ? string.Empty
                    : it.Name
            }).Select(it => new
            {
                GroupCount = it.Count(),
                it.Key,
                ValueCalculated_Min = it.Min(e => e.CalculatedValue),
                ValueCalculated_Max = it.Max(e => e.CalculatedValue),
                Count = it.Count(e => e.Link != null)
                    
            }).Select(it => new
            {
                it.Key.Name,
                Id = Guid.NewGuid(),
                _Count = it.GroupCount,
                it.ValueCalculated_Min,
                it.ValueCalculated_Max,
                it.Count
            })
            .ToArray();
            
        // OK
        _ = s.Query.All<TestEntity>()
            .GroupBy(it => new
            {
                Name = it.Name == null
                    ? string.Empty
                    : it.Name
            }).Select(it => new
            {
                GroupCount = it.Count(),
                it.Key,
                ValueCalculated_Min = it.Min(e => e.Link.Value - e.Value),
                ValueCalculated_Max = it.Max(e => e.Link.Value - e.Value)
            }).Select(it => new
            {
                it.Key.Name,
                Id = Guid.NewGuid(),
                _Count = it.GroupCount,
                it.ValueCalculated_Min,
                it.ValueCalculated_Max
            })
            .ToArray();

        // FAIL
        _ = s.Query.All<TestEntity>()
            .GroupBy(it => new
            {
                Name = it.Name == null
                    ? string.Empty
                    : it.Name
            }).Select(it => new
            {
                GroupCount = it.Count(),
                it.Key,
                ValueCalculated_Min = it.Min(e => e.CalculatedValue),
                ValueCalculated_Max = it.Max(e => e.CalculatedValue)
            }).Select(it => new
            {
                it.Key.Name,
                Id = Guid.NewGuid(),
                _Count = it.GroupCount,
                it.ValueCalculated_Min,
                it.ValueCalculated_Max
            })
            .ToArray();
    }
    
    [HierarchyRoot]
    public class LinkEntity : Entity
    {
        public LinkEntity(Session session) : base(session)
        {
        }

        [Key] [Field(Nullable = false)] public int Id { get; set; }

        [Field] public decimal? Value { get; set; }
    }
    
    [HierarchyRoot]
    public class TestEntity : Entity
    {
        public TestEntity(Session session) : base(session)
        {
        }

        [Key] [Field(Nullable = false)] public int Id { get; set; }

        [Field] public string Name { get; set; }
        
        [Field] public LinkEntity Link { get; set; }

        [Field(Nullable = true)] public decimal? Value { get; set; }
        
        public decimal? CalculatedValue { get; set; }
    }
}

Exception

Unhandled exception. Xtensive.Orm.QueryTranslationException: Unable to translate 'Query.All().GroupBy(it => new @<Name>((it.Name == null)
? .Empty
: it.Name)).Select(it => new @<GroupCount, Key, ValueCalculated_Min, ValueCalculated_Max>(
it.Count(),
it.Key,
it.Min(e => e.CalculatedValue),
it.Max(e => e.CalculatedValue)
)).Select(it => new @<Name, Id, _Count, ValueCalculated_Min, ValueCalculated_Max>(
it.Key.Name,
Guid.NewGuid(),
it.GroupCount,
it.ValueCalculated_Min,
it.ValueCalculated_Max
))' expression. See inner exception for details.
---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
at System.Collections.Generic.List`1.get_Item(Int32 index)
at Xtensive.Orm.Rse.Providers.AggregateProvider..ctor(CompilableProvider source, Int32[] groupIndexes, AggregateColumnDescriptor[] columnDescriptors)
at Xtensive.Orm.Linq.Translator.VisitAggregate(Expression source, MethodInfo method, LambdaExpression argument, Boolean isRoot, MethodCallExpression expressionPart)
at Xtensive.Orm.Linq.Translator.VisitQueryableMethod(MethodCallExpression mc, QueryableMethodKind methodKind)
at Xtensive.Linq.QueryableVisitor.VisitMethodCall(MethodCallExpression mc)
at Xtensive.Orm.Linq.Translator.VisitMethodCall(MethodCallExpression mc)
at Xtensive.Linq.ExpressionVisitor`1.Visit(Expression e)
at Xtensive.Orm.Linq.Translator.Visit(Expression e)
at Xtensive.Orm.Linq.Translator.VisitNewExpressionArguments(NewExpression n)
at Xtensive.Orm.Linq.Translator.VisitNew(NewExpression newExpression)
at Xtensive.Linq.ExpressionVisitor`1.Visit(Expression e)
at Xtensive.Orm.Linq.Translator.Visit(Expression e)
at Xtensive.Orm.Linq.Translator.VisitLambda(LambdaExpression le)
at Xtensive.Orm.Linq.Translator.BuildProjection(LambdaExpression le)
at Xtensive.Orm.Linq.Translator.VisitSelect(Expression expression, LambdaExpression le)
at Xtensive.Orm.Linq.Translator.VisitQueryableMethod(MethodCallExpression mc, QueryableMethodKind methodKind)
at Xtensive.Linq.QueryableVisitor.VisitMethodCall(MethodCallExpression mc)
at Xtensive.Orm.Linq.Translator.VisitMethodCall(MethodCallExpression mc)
at Xtensive.Linq.ExpressionVisitor`1.Visit(Expression e)
at Xtensive.Orm.Linq.Translator.Visit(Expression e)
at Xtensive.Orm.Linq.Translator.VisitSequence(Expression sequenceExpression, Expression expressionPart)
at Xtensive.Orm.Linq.Translator.VisitSequence(Expression sequenceExpression)
at Xtensive.Orm.Linq.Translator.VisitSelect(Expression expression, LambdaExpression le)
at Xtensive.Orm.Linq.Translator.VisitQueryableMethod(MethodCallExpression mc, QueryableMethodKind methodKind)
at Xtensive.Linq.QueryableVisitor.VisitMethodCall(MethodCallExpression mc)
at Xtensive.Orm.Linq.Translator.VisitMethodCall(MethodCallExpression mc)
at Xtensive.Linq.ExpressionVisitor`1.Visit(Expression e)
at Xtensive.Orm.Linq.Translator.Visit(Expression e)
at Xtensive.Orm.Linq.Translator.Translate()
at Xtensive.Orm.Linq.QueryProvider.Translate(Expression expression, CompilerConfiguration compilerConfiguration)
--- End of inner exception stack trace ---
at Xtensive.Orm.Linq.QueryProvider.Translate(Expression expression, CompilerConfiguration compilerConfiguration)
at Xtensive.Orm.Linq.QueryProvider.Translate(Expression expression)
at Xtensive.Orm.Linq.QueryProvider.Execute[TResult](Expression expression, Func`4 runQuery)
at Xtensive.Orm.Linq.QueryProvider.ExecuteSequence[T](Expression expression)
at Xtensive.Orm.Linq.Queryable`1.GetEnumerator()
at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at Program.Main(String[] args) in /Users/anton.guschin/RiderProjects/DoTest/DoTest/Program.cs:line 108
at Program.Main(String[] args) in /Users/anton.guschin/RiderProjects/DoTest/DoTest/Program.cs:line 108
at Program.Main(String[] args) in /Users/anton.guschin/RiderProjects/DoTest/DoTest/Program.cs:line 108
at Program.Main(String[] args) in /Users/anton.guschin/RiderProjects/DoTest/DoTest/Program.cs:line 108
at Program.<Main>(String[] args)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions