dataobjects-net icon indicating copy to clipboard operation
dataobjects-net copied to clipboard

Mistreating ENUMs whenever they are backed by something else than int

Open ondrejtucny opened this issue 1 year ago • 7 comments

I am running into repeated issues whenever I work with enum fields which are backed by anything else but int.

This simple query:

// fetch all current CNP settings for the given cards
var projection =
    from cardSec in qe.All<Model.CardSecurity>()
    join cnp in qe.All<Model.CardCnpSetting>() on cardSec equals cnp.AsCurrent
    where QueryableExtensions.In<int>(cardSec.CardID, parentKeys)
        && cnp.State == HistoryTrackedItemState.Current
    select new { cardSec.CardID, cnp };

causes an exception:

Xtensive.Orm.QueryTranslationException: 'Unable to translate 'Query.All().Join(
  Query.All(),
  cardSec => cardSec,
  cnp => cnp.AsCurrent,
  (cardSec, cnp) => new @<cardSec, cnp>(
    cardSec,
    cnp
  )
).Where(<>h__TransparentIdentifier0 => (<>h__TransparentIdentifier0.cardSec.CardID.In(@.parentKeys) && (((Int32)<>h__TransparentIdentifier0.cnp.State) == 5))).Select(<>h__TransparentIdentifier0 => new @<CardID, cnp>(
  <>h__TransparentIdentifier0.cardSec.CardID,
  <>h__TransparentIdentifier0.cnp
))' expression. See inner exception for details.'

The inner exception is an "Ambiguous match found." error. And this is the stack trace:

   at System.RuntimeType.GetPropertyImpl(String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
   at System.Type.GetProperty(String name, BindingFlags bindingAttr)
   at Xtensive.Orm.Linq.Translator.VisitMemberAccess(MemberExpression ma)
   at Xtensive.Linq.ExpressionVisitor`1.Visit(Expression e)
   at Xtensive.Linq.ExpressionVisitor.VisitUnary(UnaryExpression u)
   at Xtensive.Orm.Linq.Translator.VisitUnary(UnaryExpression u)
   at Xtensive.Linq.ExpressionVisitor`1.Visit(Expression e)
   at Xtensive.Orm.Linq.Translator.VisitBinary(BinaryExpression binaryExpression)
   at Xtensive.Linq.ExpressionVisitor`1.Visit(Expression e)
   at Xtensive.Orm.Linq.Translator.VisitBinary(BinaryExpression binaryExpression)
   at Xtensive.Linq.ExpressionVisitor`1.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.ExpressionVisitor`1.Visit(Expression e)
   at Xtensive.Orm.Linq.Translator.VisitSequence(Expression sequenceExpression, Expression expressionPart)
   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.Translate()
   at Xtensive.Orm.Linq.QueryProvider.Translate(Expression expression, CompilerConfiguration compilerConfiguration)

I can try updating to the latest master, in a few days, to confirm this as a pending bug. However, I do believe this has a similar root cause as the mistreatment of non-int fields in general. I have seen DO generate casts in SQL queries, completely unnecessary, such as this: …AND ( CAST([a].[id_arch] AS integer) = 0));, where id_arch is a smallint column (short in C#).

It's a pain and I hope @alex-kulakov and the team will pay attention to this. I already know how to write unit tests in DO codebase, so I will try contributing at least tests to identify these issues.

ondrejtucny avatar Mar 08 '23 11:03 ondrejtucny