question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

The LINQ expression 'Is Nothing' could not be translated VB.NET

See original GitHub issue

Problem with LINQ Query, fails when expression contains “Is Nothing” / “IsNot Nothing”. The problem occurs only in project language VB.NET.

Steps to reproduce

VB.NET Dim q = (from t in DC.Customer WHERE t.telephone Is Nothing)

Exception:

InvalidOperationException: Null TypeMapping in Sql Tree
 
en Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.SqlTypeMappingVerifyingExpressionVisitor.VisitExtension(Expression node)
   en System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   en System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   en Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlBinaryExpression.VisitChildren(ExpressionVisitor visitor)
   en Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.SqlTypeMappingVerifyingExpressionVisitor.VisitExtension(Expression node)
   en System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   en System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   en Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlBinaryExpression.VisitChildren(ExpressionVisitor visitor)
   en Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.SqlTypeMappingVerifyingExpressionVisitor.VisitExtension(Expression node)
   en System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   en System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   en Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlBinaryExpression.VisitChildren(ExpressionVisitor visitor)
   en Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.SqlTypeMappingVerifyingExpressionVisitor.VisitExtension(Expression node)
   en System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   en System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   en Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlBinaryExpression.VisitChildren(ExpressionVisitor visitor)
   en Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.SqlTypeMappingVerifyingExpressionVisitor.VisitExtension(Expression node)
   en System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   en System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   en Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.Translate(Expression expression)
   en Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateWhere(ShapedQueryExpression source, LambdaExpression predicate)
   en Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   en Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   en System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   en System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   en Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   en Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   en System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   en System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   en Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   en Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
   en Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
   en Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
   en Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
   en Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   en Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
   en Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
   en Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
   en System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
   en Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.<ToListAsync>d__64`1.MoveNext()
   en System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   en System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   en System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()

The same query in C# project works perfectly. The traslation: SELECT * FROM customer where telephone IS NULL

@roji

Further technical details

EF Core version: 3.1 Database provider: (e.g. Microsoft.EntityFrameworkCore.SqlServer) Target framework: .NET 4.6.1 Operating system: Windows 10 Pro IDE: Visual Studio 2019 16.4

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
ChristophWeigertcommented, Jan 2, 2021

@ajcvickers Found a suitable solution for me. The EF Core Project is C# so I combined this commit (https://github.com/dotnet/efcore/pull/21125) with https://github.com/dotnet/efcore/issues/19592#issuecomment-577823867

  • EF Core 3.1.10
  • VS 2019
  • VB.NET WebForms Targeting 4.7.2
  • C# EF Core Project multitargeting .NET Standard 2.1 / .NET 4.7.2

Base files are from https://github.com/dotnet/efcore/issues/19592#issuecomment-577823867

LanguageNormalizingExpressionVisitor.cs

using System;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Internal;

namespace XY
{
    /// <summary>
    ///     Normalizes certain language-specific aspects of the expression trees produced by languages other
    ///     than C#, e.g. Visual Basic.
    /// </summary>
    public class LanguageNormalizingExpressionVisitor : ExpressionVisitor
    {
        private static readonly MethodInfo _stringCompareWithComparisonMethod
            = typeof(string).GetRuntimeMethod(
                nameof(string.Compare),
                new[]
                {
                    typeof(string), typeof(string), typeof(StringComparison)
                });

        private static readonly MethodInfo _stringCompareWithoutComparisonMethod
            = typeof(string).GetRuntimeMethod(
                nameof(string.Compare),
                new[]
                {
                    typeof(string), typeof(string)
                });

        private static readonly MethodInfo _stringEqualsMethod
            = typeof(string).GetRuntimeMethod(
                nameof(string.Equals),
                new[]
                {
                    typeof(string), typeof(string), typeof(StringComparison)
                });
        
        private static Expression TryRemoveImplicitConvert(Expression expression)
        {
            if (expression is UnaryExpression unaryExpression
                && (unaryExpression.NodeType    == ExpressionType.Convert
                    || unaryExpression.NodeType == ExpressionType.ConvertChecked))
            {
                var innerType = unaryExpression.Operand.Type.UnwrapNullableType();
                if (innerType.IsEnum)
                {
                    innerType = Enum.GetUnderlyingType(innerType);
                }

                var convertedType = expression.Type.UnwrapNullableType();

                if (innerType == convertedType
                    || (convertedType == typeof(int)
                        && (innerType    == typeof(byte)
                            || innerType == typeof(sbyte)
                            || innerType == typeof(char)
                            || innerType == typeof(short)
                            || innerType == typeof(ushort))))
                {
                    return TryRemoveImplicitConvert(unaryExpression.Operand);
                }
            }

            return expression;
        }

        static bool TryUnwrapConvertToObject(Expression expression, out Expression? operand)
        {
            if (expression is UnaryExpression convertExpression
                && (convertExpression.NodeType    == ExpressionType.Convert
                    || convertExpression.NodeType == ExpressionType.ConvertChecked)
                && expression.Type == typeof(object))
            {
                operand = convertExpression.Operand;
                return true;
            }

            operand = null;
            return false;
        }

        protected override Expression VisitBinary(BinaryExpression binaryExpression)
        {
            // Remove convert-to-object nodes if both sides have them, or if the other side is null constant
            Expression left = TryRemoveImplicitConvert(binaryExpression.Left);
            Expression right = TryRemoveImplicitConvert(binaryExpression.Right);

            bool isLeftConvertToObject = TryUnwrapConvertToObject(left, out Expression? leftOperand);
            bool isRightConvertToObject = TryUnwrapConvertToObject(right, out Expression? rightOperand);
            if (isLeftConvertToObject && isRightConvertToObject)
            {
                left = leftOperand!;
                right = rightOperand!;
            }
#pragma warning disable EF1001 // Internal EF Core API usage.
            else if (isLeftConvertToObject && right.IsNullConstantExpression())
            {
                left = leftOperand!;
            }
            else if (isRightConvertToObject && left.IsNullConstantExpression())
#pragma warning restore EF1001 // Internal EF Core API usage.
            {
                right = rightOperand!;
            }



            Expression? visitedLeft = this.Visit(left);
            Expression? visitedRight = this.Visit(right);

            // In VB.NET, str1 = str2 yields CompareString(str1, str2, false) == 0.
            // Rewrite this is as a regular equality node.
            if (binaryExpression.NodeType    == ExpressionType.Equal
                || binaryExpression.NodeType == ExpressionType.NotEqual)
            {
                var (compareStringExpression, otherExpression) =
                    IsStringCompare(visitedLeft)
                        ? ((MethodCallExpression) visitedLeft, visitedRight)
                        : IsStringCompare(visitedRight)
                            ? ((MethodCallExpression) visitedRight, visitedLeft)
                            : (null, null);

                if (compareStringExpression?.Method == _stringCompareWithoutComparisonMethod)
                {
                    compareStringExpression = Expression.Call(
                        _stringCompareWithComparisonMethod,
                        compareStringExpression.Arguments[0],
                        compareStringExpression.Arguments[1],
                        Expression.Constant(StringComparison.Ordinal));
                }

                if (compareStringExpression != null
                    && (compareStringExpression.Arguments[2] as ConstantExpression)?.Value is StringComparison stringComparison
                    && otherExpression is ConstantExpression otherConstantExpression
                    && (int) otherConstantExpression.Value == 0)
                {
                    switch (stringComparison)
                    {
                        case StringComparison.Ordinal:
                            return Expression.MakeBinary(
                                binaryExpression.NodeType,
                                compareStringExpression.Arguments[0],
                                compareStringExpression.Arguments[1]);

                        case StringComparison.OrdinalIgnoreCase:
                            MethodCallExpression? stringEqualsExpression = Expression.Call(
                                _stringEqualsMethod,
                                compareStringExpression.Arguments[0],
                                compareStringExpression.Arguments[1],
                                Expression.Constant(StringComparison.OrdinalIgnoreCase)
                            );
                            return binaryExpression.NodeType == ExpressionType.Equal
                                ? (Expression) stringEqualsExpression
                                : Expression.Not(stringEqualsExpression);
                    }
                }
            }

            return binaryExpression.Update(visitedLeft, binaryExpression.Conversion, visitedRight);

            static bool IsStringCompare(Expression expression)
            {
                return expression is MethodCallExpression methodCallExpression
                       && (methodCallExpression.Method    == _stringCompareWithComparisonMethod
                           || methodCallExpression.Method == _stringCompareWithoutComparisonMethod);
            }
        }

        protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression)
        {
            MethodCallExpression? visited = (MethodCallExpression) base.VisitMethodCall(methodCallExpression);

            // In VB.NET, comparison operators between strings (equality, greater-than, less-than) yield
            // calls to a VB-specific CompareString method. Normalize that to string.Compare.
            if (visited.Method.Name                        == "CompareString"
                && visited.Method.DeclaringType?.Name      == "Operators"
                && visited.Method.DeclaringType?.Namespace == "Microsoft.VisualBasic.CompilerServices"
                && visited.Object                          == null
                && visited.Arguments.Count                 == 3
                && visited.Arguments[2] is ConstantExpression textCompareConstantExpression)
            {
                return (bool) textCompareConstantExpression.Value
                    ? Expression.Call(
                        _stringCompareWithComparisonMethod,
                        visited.Arguments[0],
                        visited.Arguments[1],
                        Expression.Constant(StringComparison.OrdinalIgnoreCase))
                    : Expression.Call(
                        _stringCompareWithoutComparisonMethod,
                        visited.Arguments[0],
                        visited.Arguments[1]);
            }

            return visited;
        }
    }
}

SharedTypeExtensions.cs

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using JetBrains.Annotations;

#nullable enable

// ReSharper disable once CheckNamespace
namespace System
{
    [DebuggerStepThrough]
    internal static class SharedTypeExtensions
    {
        private static readonly Dictionary<Type, string> _builtInTypeNames = new Dictionary<Type, string>
        {
            { typeof(bool), "bool" },
            { typeof(byte), "byte" },
            { typeof(char), "char" },
            { typeof(decimal), "decimal" },
            { typeof(double), "double" },
            { typeof(float), "float" },
            { typeof(int), "int" },
            { typeof(long), "long" },
            { typeof(object), "object" },
            { typeof(sbyte), "sbyte" },
            { typeof(short), "short" },
            { typeof(string), "string" },
            { typeof(uint), "uint" },
            { typeof(ulong), "ulong" },
            { typeof(ushort), "ushort" },
            { typeof(void), "void" }
        };

        public static Type UnwrapNullableType(this Type type)
            => Nullable.GetUnderlyingType(type) ?? type;

        public static bool IsNullableValueType(this Type type)
            => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);

        public static bool IsNullableType(this Type type)
            => !type.IsValueType || type.IsNullableValueType();

        public static bool IsValidEntityType(this Type type)
            => type.IsClass;

        public static bool IsPropertyBagType(this Type type)
        {
            if (type.IsGenericTypeDefinition)
            {
                return false;
            }

            var types = GetGenericTypeImplementations(type, typeof(IDictionary<,>));
            return types.Any(
                t => t.GetGenericArguments()[0] == typeof(string)
                    && t.GetGenericArguments()[1] == typeof(object));
        }

        public static Type MakeNullable(this Type type, bool nullable = true)
            => type.IsNullableType() == nullable
                ? type
                : nullable
                    ? typeof(Nullable<>).MakeGenericType(type)
                    : type.UnwrapNullableType();

        public static bool IsNumeric(this Type type)
        {
            type = type.UnwrapNullableType();

            return type.IsInteger()
                || type == typeof(decimal)
                || type == typeof(float)
                || type == typeof(double);
        }

        public static bool IsInteger(this Type type)
        {
            type = type.UnwrapNullableType();

            return type == typeof(int)
                || type == typeof(long)
                || type == typeof(short)
                || type == typeof(byte)
                || type == typeof(uint)
                || type == typeof(ulong)
                || type == typeof(ushort)
                || type == typeof(sbyte)
                || type == typeof(char);
        }

        public static bool IsSignedInteger(this Type type)
            => type == typeof(int)
                || type == typeof(long)
                || type == typeof(short)
                || type == typeof(sbyte);

        public static bool IsAnonymousType(this Type type)
            => type.Name.StartsWith("<>", StringComparison.Ordinal)
                && type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), inherit: false).Length > 0
                && type.Name.Contains("AnonymousType");

        public static bool IsTupleType(this Type type)
        {
            if (type == typeof(Tuple))
            {
                return true;
            }

            if (type.IsGenericType)
            {
                var genericDefinition = type.GetGenericTypeDefinition();
                if (genericDefinition == typeof(Tuple<>)
                    || genericDefinition == typeof(Tuple<,>)
                    || genericDefinition == typeof(Tuple<,,>)
                    || genericDefinition == typeof(Tuple<,,,>)
                    || genericDefinition == typeof(Tuple<,,,,>)
                    || genericDefinition == typeof(Tuple<,,,,,>)
                    || genericDefinition == typeof(Tuple<,,,,,,>)
                    || genericDefinition == typeof(Tuple<,,,,,,,>)
                    || genericDefinition == typeof(Tuple<,,,,,,,>))
                {
                    return true;
                }
            }

            return false;
        }

        public static PropertyInfo? GetAnyProperty(this Type type, string name)
        {
            var props = type.GetRuntimeProperties().Where(p => p.Name == name).ToList();
            if (props.Count > 1)
            {
                throw new AmbiguousMatchException();
            }

            return props.SingleOrDefault();
        }

        public static MethodInfo GetRequiredMethod(this Type type, string name, params Type[] parameters)
        {
            var method = type.GetTypeInfo().GetMethod(name, parameters);

            if (method == null
                && parameters.Length == 0)
            {
                method = type.GetMethod(name);
            }

            if (method == null)
            {
                throw new InvalidOperationException();
            }

            return method;
        }

        public static PropertyInfo GetRequiredProperty(this Type type, string name)
        {
            var property = type.GetTypeInfo().GetProperty(name);
            if (property == null)
            {
                throw new InvalidOperationException();
            }

            return property;
        }

        public static FieldInfo GetRequiredDeclaredField(this Type type, string name)
        {
            var field = type.GetTypeInfo().GetDeclaredField(name);
            if (field == null)
            {
                throw new InvalidOperationException();
            }

            return field;
        }

        public static MethodInfo GetRequiredDeclaredMethod(this Type type, string name)
        {
            var method = type.GetTypeInfo().GetDeclaredMethod(name);
            if (method == null)
            {
                throw new InvalidOperationException();
            }

            return method;
        }

        public static PropertyInfo GetRequiredDeclaredProperty(this Type type, string name)
        {
            var property = type.GetTypeInfo().GetDeclaredProperty(name);
            if (property == null)
            {
                throw new InvalidOperationException();
            }

            return property;
        }

        public static MethodInfo GetRequiredRuntimeMethod(this Type type, string name, params Type[] parameters)
        {
            var method = type.GetTypeInfo().GetRuntimeMethod(name, parameters);
            if (method == null)
            {
                throw new InvalidOperationException();
            }

            return method;
        }

        public static PropertyInfo GetRequiredRuntimeProperty(this Type type, string name)
        {
            var property = type.GetTypeInfo().GetRuntimeProperty(name);
            if (property == null)
            {
                throw new InvalidOperationException();
            }

            return property;
        }

        public static bool IsInstantiable(this Type type)
            => !type.IsAbstract
                && !type.IsInterface
                && (!type.IsGenericType || !type.IsGenericTypeDefinition);

        public static Type UnwrapEnumType(this Type type)
        {
            var isNullable = type.IsNullableType();
            var underlyingNonNullableType = isNullable ? type.UnwrapNullableType() : type;
            if (!underlyingNonNullableType.IsEnum)
            {
                return type;
            }

            var underlyingEnumType = Enum.GetUnderlyingType(underlyingNonNullableType);
            return isNullable ? MakeNullable(underlyingEnumType) : underlyingEnumType;
        }

        public static Type GetSequenceType(this Type type)
        {
            var sequenceType = TryGetSequenceType(type);
            if (sequenceType == null)
            {
                // TODO: Add exception message
                throw new ArgumentException();
            }

            return sequenceType;
        }

#nullable enable

        public static Type? TryGetSequenceType(this Type type)
            => type.TryGetElementType(typeof(IEnumerable<>))
                ?? type.TryGetElementType(typeof(IAsyncEnumerable<>));

        public static Type? TryGetElementType(this Type type, Type interfaceOrBaseType)
        {
            if (type.IsGenericTypeDefinition)
            {
                return null;
            }

            var types = GetGenericTypeImplementations(type, interfaceOrBaseType);

            Type? singleImplementation = null;
            foreach (var implementation in types)
            {
                if (singleImplementation == null)
                {
                    singleImplementation = implementation;
                }
                else
                {
                    singleImplementation = null;
                    break;
                }
            }

            return singleImplementation?.GenericTypeArguments.FirstOrDefault();
        }

#nullable disable

        public static bool IsCompatibleWith(this Type propertyType, Type fieldType)
        {
            if (propertyType.IsAssignableFrom(fieldType)
                || fieldType.IsAssignableFrom(propertyType))
            {
                return true;
            }

            var propertyElementType = propertyType.TryGetSequenceType();
            var fieldElementType = fieldType.TryGetSequenceType();

            return propertyElementType != null
                && fieldElementType != null
                && IsCompatibleWith(propertyElementType, fieldElementType);
        }

        public static IEnumerable<Type> GetGenericTypeImplementations(this Type type, Type interfaceOrBaseType)
        {
            var typeInfo = type.GetTypeInfo();
            if (!typeInfo.IsGenericTypeDefinition)
            {
                var baseTypes = interfaceOrBaseType.GetTypeInfo().IsInterface
                    ? typeInfo.ImplementedInterfaces
                    : type.GetBaseTypes();
                foreach (var baseType in baseTypes)
                {
                    if (baseType.IsGenericType
                        && baseType.GetGenericTypeDefinition() == interfaceOrBaseType)
                    {
                        yield return baseType;
                    }
                }

                if (type.IsGenericType
                    && type.GetGenericTypeDefinition() == interfaceOrBaseType)
                {
                    yield return type;
                }
            }
        }

        public static IEnumerable<Type> GetBaseTypes(this Type type)
        {
            type = type.BaseType;

            while (type != null)
            {
                yield return type;

                type = type.BaseType;
            }
        }

        public static IEnumerable<Type> GetTypesInHierarchy(this Type type)
        {
            while (type != null)
            {
                yield return type;

                type = type.BaseType;
            }
        }

        public static ConstructorInfo GetDeclaredConstructor(this Type type, Type[] types)
        {
            types ??= Array.Empty<Type>();

            return type.GetTypeInfo().DeclaredConstructors
                .SingleOrDefault(
                    c => !c.IsStatic
                        && c.GetParameters().Select(p => p.ParameterType).SequenceEqual(types));
        }

        public static IEnumerable<PropertyInfo> GetPropertiesInHierarchy(this Type type, string name)
        {
            do
            {
                var typeInfo = type.GetTypeInfo();
                foreach (var propertyInfo in typeInfo.DeclaredProperties)
                {
                    if (propertyInfo.Name.Equals(name, StringComparison.Ordinal)
                        && !(propertyInfo.GetMethod ?? propertyInfo.SetMethod).IsStatic)
                    {
                        yield return propertyInfo;
                    }
                }

                type = typeInfo.BaseType;
            }
            while (type != null);
        }

        // Looking up the members through the whole hierarchy allows to find inherited private members.
        public static IEnumerable<MemberInfo> GetMembersInHierarchy(this Type type)
        {
            do
            {
                // Do the whole hierarchy for properties first since looking for fields is slower.
                foreach (var propertyInfo in type.GetRuntimeProperties().Where(pi => !(pi.GetMethod ?? pi.SetMethod).IsStatic))
                {
                    yield return propertyInfo;
                }

                foreach (var fieldInfo in type.GetRuntimeFields().Where(f => !f.IsStatic))
                {
                    yield return fieldInfo;
                }

                type = type.BaseType;
            }
            while (type != null);
        }

        public static IEnumerable<MemberInfo> GetMembersInHierarchy(this Type type, string name)
            => type.GetMembersInHierarchy().Where(m => m.Name == name);

        private static readonly Dictionary<Type, object> _commonTypeDictionary = new Dictionary<Type, object>
        {
#pragma warning disable IDE0034 // Simplify 'default' expression - default causes default(object)
            { typeof(int), default(int) },
            { typeof(Guid), default(Guid) },
            { typeof(DateTime), default(DateTime) },
            { typeof(DateTimeOffset), default(DateTimeOffset) },
            { typeof(long), default(long) },
            { typeof(bool), default(bool) },
            { typeof(double), default(double) },
            { typeof(short), default(short) },
            { typeof(float), default(float) },
            { typeof(byte), default(byte) },
            { typeof(char), default(char) },
            { typeof(uint), default(uint) },
            { typeof(ushort), default(ushort) },
            { typeof(ulong), default(ulong) },
            { typeof(sbyte), default(sbyte) }
#pragma warning restore IDE0034 // Simplify 'default' expression
        };

        public static object GetDefaultValue(this Type type)
        {
            if (!type.IsValueType)
            {
                return null;
            }

            // A bit of perf code to avoid calling Activator.CreateInstance for common types and
            // to avoid boxing on every call. This is about 50% faster than just calling CreateInstance
            // for all value types.
            return _commonTypeDictionary.TryGetValue(type, out var value)
                ? value
                : Activator.CreateInstance(type);
        }

        public static IEnumerable<TypeInfo> GetConstructibleTypes(this Assembly assembly)
            => assembly.GetLoadableDefinedTypes().Where(
                t => !t.IsAbstract
                    && !t.IsGenericTypeDefinition);

        public static IEnumerable<TypeInfo> GetLoadableDefinedTypes(this Assembly assembly)
        {
            try
            {
                return assembly.DefinedTypes;
            }
            catch (ReflectionTypeLoadException ex)
            {
                return ex.Types.Where(t => t != null).Select(IntrospectionExtensions.GetTypeInfo);
            }
        }

        public static bool IsQueryableType(this Type type)
        {
            if (type.IsGenericType
                && type.GetGenericTypeDefinition() == typeof(IQueryable<>))
            {
                return true;
            }

            return type.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IQueryable<>));
        }

        /// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        public static string DisplayName(this Type type, bool fullName = true)
        {
            var stringBuilder = new StringBuilder();
            ProcessType(stringBuilder, type, fullName);
            return stringBuilder.ToString();
        }

        private static void ProcessType(StringBuilder builder, Type type, bool fullName)
        {
            if (type.IsGenericType)
            {
                var genericArguments = type.GetGenericArguments();
                ProcessGenericType(builder, type, genericArguments, genericArguments.Length, fullName);
            }
            else if (type.IsArray)
            {
                ProcessArrayType(builder, type, fullName);
            }
            else if (_builtInTypeNames.TryGetValue(type, out var builtInName))
            {
                builder.Append(builtInName);
            }
            else if (!type.IsGenericParameter)
            {
                builder.Append(fullName ? type.FullName : type.Name);
            }
        }

        private static void ProcessArrayType(StringBuilder builder, Type type, bool fullName)
        {
            var innerType = type;
            while (innerType.IsArray)
            {
                innerType = innerType.GetElementType();
            }

            ProcessType(builder, innerType, fullName);

            while (type.IsArray)
            {
                builder.Append('[');
                builder.Append(',', type.GetArrayRank() - 1);
                builder.Append(']');
                type = type.GetElementType();
            }
        }

        private static void ProcessGenericType(StringBuilder builder, Type type, Type[] genericArguments, int length, bool fullName)
        {
            var offset = type.IsNested ? type.DeclaringType.GetGenericArguments().Length : 0;

            if (fullName)
            {
                if (type.IsNested)
                {
                    ProcessGenericType(builder, type.DeclaringType, genericArguments, offset, fullName);
                    builder.Append('+');
                }
                else
                {
                    builder.Append(type.Namespace);
                    builder.Append('.');
                }
            }

            var genericPartIndex = type.Name.IndexOf('`');
            if (genericPartIndex <= 0)
            {
                builder.Append(type.Name);
                return;
            }

            builder.Append(type.Name, 0, genericPartIndex);
            builder.Append('<');

            for (var i = offset; i < length; i++)
            {
                ProcessType(builder, genericArguments[i], fullName);
                if (i + 1 == length)
                {
                    continue;
                }

                builder.Append(',');
                if (!genericArguments[i + 1].IsGenericParameter)
                {
                    builder.Append(' ');
                }
            }

            builder.Append('>');
        }

        public static IEnumerable<string> GetNamespaces(this Type type)
        {
            if (_builtInTypeNames.ContainsKey(type))
            {
                yield break;
            }

            yield return type.Namespace;

            if (type.IsGenericType)
            {
                foreach (var typeArgument in type.GenericTypeArguments)
                {
                    foreach (var ns in typeArgument.GetNamespaces())
                    {
                        yield return ns;
                    }
                }
            }
        }

        public static ConstantExpression GetDefaultValueConstant(this Type type)
            => (ConstantExpression)_generateDefaultValueConstantMethod
                .MakeGenericMethod(type).Invoke(null, Array.Empty<object>());

        private static readonly MethodInfo _generateDefaultValueConstantMethod =
            typeof(SharedTypeExtensions).GetTypeInfo().GetDeclaredMethod(nameof(GenerateDefaultValueConstant));

        private static ConstantExpression GenerateDefaultValueConstant<TDefault>()
            => Expression.Constant(default(TDefault), typeof(TDefault));
    }
}

VisualBasicRelationalQueryTranslationPreprocessor.cs

using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore.Query;

namespace XY
{
    /// <summary>
    ///     VisualBasicRelationalQueryTranslationPreprocessor
    /// </summary>
    public class VisualBasicRelationalQueryTranslationPreprocessor : RelationalQueryTranslationPreprocessor
    {
        /// <summary>
        ///     Initializes a new instance of the <see cref="VisualBasicRelationalQueryTranslationPreprocessor" /> class.
        /// </summary>
        /// <param name="dependencies">The dependencies.</param>
        /// <param name="relationalDependencies">The relational dependencies.</param>
        /// <param name="queryCompilationContext">The query compilation context.</param>
        public VisualBasicRelationalQueryTranslationPreprocessor(QueryTranslationPreprocessorDependencies dependencies,
                                                                 RelationalQueryTranslationPreprocessorDependencies relationalDependencies,
                                                                 QueryCompilationContext queryCompilationContext)
            : base(dependencies, relationalDependencies, queryCompilationContext)
        {
        }

        public override Expression Process(Expression query)
        {
            query = new LanguageNormalizingExpressionVisitor().Visit(query)!;
            return base.Process(query);
        }
    }
}

VisualBasicRelationalQueryTranslationPreprocessorFactory .cs

using Microsoft.EntityFrameworkCore.Query;

namespace XY
{
    /// <summary>
    ///     VisualBasicRelationalQueryTranslationPreprocessorFactory
    /// </summary>
    public class VisualBasicRelationalQueryTranslationPreprocessorFactory : IQueryTranslationPreprocessorFactory
    {
        private readonly QueryTranslationPreprocessorDependencies dependencies;
        private readonly RelationalQueryTranslationPreprocessorDependencies relationalDependencies;

        /// <summary>
        ///     Initializes a new instance of the <see cref="VisualBasicRelationalQueryTranslationPreprocessorFactory" /> class.
        /// </summary>
        /// <param name="dependencies">The dependencies.</param>
        /// <param name="relationalDependencies">The relational dependencies.</param>
        public VisualBasicRelationalQueryTranslationPreprocessorFactory(QueryTranslationPreprocessorDependencies dependencies,
                                                                        RelationalQueryTranslationPreprocessorDependencies relationalDependencies)
        {
            this.dependencies = dependencies;
            this.relationalDependencies = relationalDependencies;
        }

        /// <summary>
        ///     Creates the specified query compilation context.
        /// </summary>
        /// <param name="queryCompilationContext">The query compilation context.</param>
        /// <returns></returns>
        public virtual QueryTranslationPreprocessor Create(QueryCompilationContext queryCompilationContext)
        {
            return new VisualBasicRelationalQueryTranslationPreprocessor(this.dependencies, this.relationalDependencies, queryCompilationContext);
        }
    }
}
0reactions
ajcvickerscommented, Jan 1, 2021

@ChristophWeigert You’ll probably need to re-write the LINQ expression tree. @smitpatel @roji Would a method translator work here?

Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - The LINQ expression could not be translated and will ...
I got this error by querying my LINQ methods in the wrong order before calling a ToListAsync call at the end. Here was...
Read more >
LINQ Expression Could not Be Translated - Microsoft Q&A
Hello everyone and thanks for the help in advance. I am creating a MVC application uisng .Net 6 and EF 6 to query...
Read more >
Invalidoperationexception: the LINQ expression
You are misusing the property and EF cannot translate that. In order to use an expression in LINQ it must be translatable to...
Read more >
Invalidoperationexception: the LINQ expression for groupby
FirstOrDefault()' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly ...
Read more >
Microsoft SQL Server 2008 R2 Unleashed - Google Books Result
When you use this C# syntax convention, you don't have to set up a finally block that ... NET objects, it's time to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found