Hello, i am getting NotSupportedException when trying to compare result of ternary conditional operator with already materialized entity. Here is how to reproduce it:

[HierarchyRoot]
public class First : Entity
{
    public First(Guid id) : base(id)
    {
    }

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

    [Field]
    public Second Second { get; set; }
}

[HierarchyRoot]
public class Second : Entity
{
    public Second(Guid id) : base(id)
    {
    }

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

class Program
{
    static void Main(string[] args)
    {
        var dc = new DomainConfiguration("sqlserver", "Data Source=.; Initial Catalog=DO41-Tests;Connection Timeout=300;Integrated Security = true;Max pool size=2");

        dc.Types.Register(typeof(Program).Assembly);

        dc.UpgradeMode = DomainUpgradeMode.Recreate;

        using (var domain = Domain.Build(dc))
        using (var session = domain.OpenSession(SessionType.Default))
        using (session.Activate())
        using (var tr = session.OpenTransaction())
        {
            var second1 = new Second(Guid.NewGuid());
            var second2 = new Second(Guid.NewGuid());

            session.Query.All<First>().Select(z => new
            {
                Id = z.Id,
                Sum = z.Second != null ? z.Second : second1,
            })
            .Where(z => z.Sum == second2)
            .ToArray();
        }
    }
}

and exception


Unhandled Exception: Xtensive.Orm.QueryTranslationException: Unable to translate 'Query.All().Select(z => new @<id, sum="">(
  z.Id,
  (z.Second != null)
    ? z.Second
    : @.second1
)).Where(z => (z.Sum == @.second2))' expression. See inner exception for details. ---> System.NotSupportedException: Both left and right part of binary expression '(IIF((Convert(Field Id, [2 ... 1]) != null), Entity Second, value(Sample.Program+<>cDisplayClas
s0_0).second1) == value(Sample.Program+<>cDisplayClass0_0).second2)' are NULL or not EntityExpression(EntityFieldExpression).
   at Xtensive.Orm.Linq.Translator.VisitBinaryRecursive(BinaryExpression binaryExpression, BinaryExpression originalBinaryExpression)
   at Xtensive.Orm.Linq.Translator.VisitBinary(BinaryExpression binaryExpression)
   at Xtensive.Linq.ExpressionVisitor1.Visit(Expression e)
   at Xtensive.Orm.Linq.Translator.Visit(Expression e)
   at Xtensive.Orm.Linq.Translator.VisitLambda(LambdaExpression le)
   at Xtensive.Orm.Linq.Translator.VisitWhere(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.ExpressionVisitor1.Visit(Expression e)
   at Xtensive.Orm.Linq.Translator.Visit(Expression e)
   at Xtensive.Orm.Linq.Translator.TranslateTResult
   at Xtensive.Orm.Linq.QueryProvider.TranslateTResult
   --- End of inner exception stack trace ---
   at Xtensive.Orm.Linq.QueryProvider.TranslateTResult
   at Xtensive.Orm.Linq.QueryProvider.TranslateTResult
   at Xtensive.Orm.Linq.QueryProvider.ExecuteTResult
   at Xtensive.Orm.Linq.Queryable1.GetEnumerator()
   at System.Linq.Buffer1..ctor(IEnumerable1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source)
   at Sample.Program.Main(String[] args) in F:\Projects\CleanDO\Sample\Program.cs:line 69

UPD: Query in inital post is wrong. It should be like

            session.Query.All<First>().Select(z => new
            {
                Id = z.Id,
                Sum = z.Second != null 
                    ? z.Second 
                    : session.Query.All<Second>().Single(x => x.Id == second1.Id),
            })
            .Where(z => z.Sum == second2)
            .ToArray();

and exception is slightly different


Unhandled Exception: Xtensive.Orm.QueryTranslationException: Unable to translate 'Query.All().Select(z => new @<id, sum="">(
  z.Id,
  (z.Second != null)
    ? z.Second
    : @.CS$<>8locals1.session.Query.All().Single(x => (x.Id == @.second1.Id))
)).Where(z => (z.Sum == @.second2))' expression. See inner exception for details. ---> System.InvalidCastException: Unable to cast object of type 'Xtensive.Orm.Linq.Expressions.MarkerExpression' to type 'Xtensive.Orm.Linq.Expressions.IEntityExpression'.
   at Xtensive.Orm.Linq.Translator.GetConditionalKeyField(Expression expression, Type keyFieldType, Int32 index)
   at Xtensive.Orm.Linq.Translator.GetConditionalKeyField(Expression expression, Type keyFieldType, Int32 index)
   at Xtensive.Orm.Linq.Translator.<>cDisplayClass3e.<getentityfields>b3d(Type type, Int32 index)
   at System.Linq.Enumerable.<selectiterator>d52.MoveNext()
   at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)
   at Xtensive.Orm.Linq.Translator.GetEntityFields(Expression expression, IEnumerable1 keyFieldTypes)
   at Xtensive.Orm.Linq.Translator.VisitBinaryRecursive(BinaryExpression binaryExpression, BinaryExpression originalBinaryExpression)
   at Xtensive.Orm.Linq.Translator.VisitBinary(BinaryExpression binaryExpression)
   at Xtensive.Linq.ExpressionVisitor1.Visit(Expression e)
   at Xtensive.Orm.Linq.Translator.Visit(Expression e)
   at Xtensive.Orm.Linq.Translator.VisitLambda(LambdaExpression le)
   at Xtensive.Orm.Linq.Translator.VisitWhere(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.ExpressionVisitor1.Visit(Expression e)
   at Xtensive.Orm.Linq.Translator.Visit(Expression e)
   at Xtensive.Orm.Linq.Translator.Translate[TResult]()
   at Xtensive.Orm.Linq.QueryProvider.Translate[TResult](Expression expression, CompilerConfiguration compilerConfiguration)
   --- End of inner exception stack trace ---
   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.Queryable1.GetEnumerator()
   at System.Linq.Buffer1..ctor(IEnumerable1 source)
   at System.Linq.Enumerable.ToArrayTSource
   at Sample.Program.Main(String[] args) in F:\Projects\CleanDO\Sample\Program.cs:line 72

asked Feb 18 '19 at 08:54

meatblob's gravatar image

meatblob
5112

edited May 21 '19 at 13:16


One Answer:

Hello meatblob

Such closures are not supported. I'm not sure that it is possible to translate into pure SQL query. The only way it will work with such closures is executing select on client side like

session.Query.All<first>().AsEnumerable().Select(z => new
            {
                Id = z.Id,
                Sum = z.Second != null ? z.Second : second1,
            })
            .Where(z => z.Sum == second2)
            .ToArray();

but it is horrible idea because it is reading of whole tables. Don't do that.

Another thing you can do is rewrite your query to avoid closure of entire entity like

session.Query.All<first>().Select(z => new
          {
            Id = z.Id,
            SumId = z.Second != null ? z.Second.Id : second1.Id,
          })
          .Select(t=> new {t.Id, Sum = session.Query.All<second>().First(s=> s.Id==t.SumId)})
          .Where(z => z.Sum == second1)
          .ToArray()

answered Feb 20 '19 at 08:26

Alexey%20Kulakov's gravatar image

Alexey Kulakov
77225

My initial post was wrong, please see the updated version.

Your solution with Id substitution works in updated query, but it has consequences - usage of this field in other ternary conditional operator later fails with UnableToTranslateException, thus forcing to make such substitutions across whole query.

(May 21 '19 at 13:16) meatblob meatblob's gravatar image
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