Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
letarak opened this issue Dec 11, 2023 · 0 comments
Open

Comments

@letarak
Copy link

letarak commented Dec 11, 2023

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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant