DO 5.0.7

Code:

using System;
using System.Linq;
using System.Transactions;
using NUnit.Framework;
using Xtensive.Orm;
using Xtensive.Orm.Configuration;

class Program
{
    static void Main(string[] args)
    {
        var sc = new SessionConfiguration("Default")
        {
            BatchSize = 25,
            DefaultIsolationLevel = IsolationLevel.ReadCommitted,
            CacheSize = 1000,
            DefaultCommandTimeout = 600,
            Options =
                SessionOptions.Default
                | SessionOptions.NonTransactionalReads
                | SessionOptions.AutoActivation
                | SessionOptions.SuppressRollbackExceptions
                | SessionOptions.ValidateEntityVersions,
        };

        var dc = new DomainConfiguration("sqlserver", @"Data Source=localhost\MSSQLSERVER2016; Initial Catalog=DO40-Tests; Integrated Security=True;Connection Timeout=5;Application Name=Werp;")
        {
            UpgradeMode = DomainUpgradeMode.Recreate
        };

        dc.Sessions.Add(sc);
        dc.Types.Register(typeof(Item));

        using (var domain = Domain.Build(dc))
        using (var session = domain.OpenSession())
        using (session.Activate())
        using (session.OpenTransaction(TransactionOpenMode.New))
        {
            var items = Session.Current.Query.All<Item>();

            var withCondFirst = items.Select(i => new { Item = i, Dec = i.Name == "1" ? i.Decimal : -i.Decimal });
            var withCondSecond = items.Select(i => new { Item = i, Dec = i.Name == "2" ? -i.Decimal : i.Decimal });

            // With conditions - ok
            Assert.DoesNotThrow(() => withCondFirst.Union(withCondSecond).ToArray());

            var withoutSelfLinkFirst = items.Select(i => new { i.Name, Dec = i.Decimal });
            var withoutSelfLinkSecond = items.Select(i => new { i.Name, Dec = -i.Decimal });

            // Without self link - ok
            Assert.DoesNotThrow(() => withoutSelfLinkFirst.Union(withoutSelfLinkSecond).ToArray());

            var withoutSelfLinkWithCondFirst = items.Select(i => new { i.Name, Dec = i.Name == "1" ? i.Decimal : -i.Decimal });
            var withoutSelfLinkWithCondSecond = items.Select(i => new { i.Name, Dec = i.Name == "2" ? -i.Decimal : i.Decimal });

            // Without self link, with condition - ok
            Assert.DoesNotThrow(() => withoutSelfLinkWithCondFirst.Union(withoutSelfLinkWithCondSecond).ToArray());

            var withoutCondUseKeyFirst = items.Select(i => new { Item = i.Key, Dec = i.Decimal });
            var withoutCondUseKeySecond = items.Select(i => new { Item = i.Key, Dec = -i.Decimal });

            // Without condition, use Key - ok
            Assert.DoesNotThrow(() => withoutCondUseKeyFirst.Union(withoutCondUseKeySecond).ToArray());

            var withoutCondFirst = items.Select(i => new { Item = i, Dec = i.Decimal });
            var withoutCondSecond = items.Select(i => new { Item = i, Dec = -i.Decimal });

            // Without condition - error
            Assert.DoesNotThrow(() => withoutCondFirst.Union(withoutCondSecond).ToArray());
        }
    }
}

[HierarchyRoot]
[Serializable]
[KeyGenerator(KeyGeneratorKind.None)]
public class Item : Entity
{
    public Item(Guid id)
        : base(id)
    {
    }

    [Field]
    [Key]
    public Guid Id { get; }

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

    [Field]
    public decimal Decimal { get; set; }
}

Exception:

An exception of type 'Xtensive.Orm.QueryTranslationException' occurred in Xtensive.Orm.dll but was not handled in user code

Additional information: Unable to translate 'Query.All().Select(i => new @<Item, Dec>(

  i,

  i.Decimal

)).Union(Query.All().Select(i => new @<Item, Dec>(

  i,

  -(i.Decimal)

)))' expression. See inner exception for details.

Inner exception:

{"Union operation can't be executed on specified sources."}

StackTrace:

at Xtensive.Orm.Linq.QueryProvider.Translate[TResult](Expression expression, CompilerConfiguration compilerConfiguration)
at Xtensive.Orm.Linq.QueryProvider.Translate[TResult](Expression expression)
at Xtensive.Orm.Linq.QueryProvider.Execute[TResult](Expression expression)
at Xtensive.Orm.Linq.Queryable`1.GetEnumerator()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at Sample.Program.<>c__DisplayClass0_0.<Main>b__4() in D:\Projects\CleanDO\Sample\Program.cs:line 71
at NUnit.Framework.Constraints.VoidInvocationDescriptor.Invoke()
at NUnit.Framework.Constraints.ExceptionInterceptor.Intercept(Object invocation)

asked Feb 01 '17 at 08:13

Anton%20Guschin's gravatar image

Anton Guschin
73303035


One Answer:

Hello Anton,

Here is particularity of translation.

In this query

 var withoutCondFirst = items.Select(i => new { Item = i, Dec = i.Decimal }); 
it gets all columns for an Item instance materialization, they are Id, TypeId, Name, Decimal. But no need to select extra column for that part
Dec = i.Decimal;
because it gets value as is, without any modification, and value may be got from the columns which are already selected.

In the query

var withoutCondSecond = items.Select(i => new { Item = i, Dec = -i.Decimal });
it gets all columns for an Item instance materialization as well. But in this case you want to get a modified value, so DO has to add extra column as a calculated column. Because of that extra column there are 5 columns instead of 4 in the first case.

And as you probably know, you can't UNION two selections with different count of columns.

I don't know if I'm able to correct such behavior somehow, but I will create a task for that issue.

answered Feb 03 '17 at 09:04

Alexey%20Kulakov's gravatar image

Alexey Kulakov
77225

Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

powered by OSQA