diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs index 3c0483e52..2ce5f7c23 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs @@ -1849,11 +1849,10 @@ private static IReadOnlySet GetNullableGroupingExpressions(IReadOnlyList<(C return nullableFields; } - private bool IsKeyCollection(Type localCollectionType) - { - return (localCollectionType.IsArray && localCollectionType.GetElementType() == WellKnownOrmTypes.Key) - || IEnumerableOfKeyType.IsAssignableFrom(localCollectionType); - } + private bool IsKeyCollection(Type localCollectionType) => + (localCollectionType.IsArray && localCollectionType.GetElementType() == WellKnownOrmTypes.Key) + || IEnumerableOfKeyType.IsAssignableFrom(localCollectionType) + || localCollectionType.IsOfGenericType(WellKnownTypes.ReadOnlySpanOfT) && localCollectionType.GetGenericArguments()[0] == WellKnownOrmTypes.Key; internal void RestoreState(in TranslatorState previousState) => State = previousState; diff --git a/Orm/Xtensive.Orm/Orm/Linq/WellKnownMembers.cs b/Orm/Xtensive.Orm/Orm/Linq/WellKnownMembers.cs index 37951de9e..d07fd5de1 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/WellKnownMembers.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/WellKnownMembers.cs @@ -249,6 +249,12 @@ public static class Enumerable public static readonly MethodInfo Cast = GetMethod(typeof(System.Linq.Enumerable), nameof(System.Linq.Enumerable.Cast), 1, 1); } + public static class MemoryExtensions + { + public static readonly MethodInfo ContainsInReadOnlySpan = typeof(System.MemoryExtensions).GetMethods() + .Where(m => m.Name == "Contains" && m.GetParameterTypes()[0].GetGenericTypeDefinition() == WellKnownTypes.ReadOnlySpanOfT).First(); + } + // IEntity public static readonly PropertyInfo IEntityKey = WellKnownOrmInterfaces.Entity.GetProperty(WellKnown.KeyFieldName); public static readonly PropertyInfo TypeId = WellKnownOrmInterfaces.Entity.GetProperty(WellKnown.TypeIdFieldName); diff --git a/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.cs b/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.cs index ace437894..5addb7b6c 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.cs @@ -90,6 +90,13 @@ private SqlExpression Visit(Expression e, bool smartNull) if (evaluator.CanBeEvaluated(e)) { if (parameterExtractor.IsParameter(e)) return VisitParameterAccess(e, smartNull); + if (e.NodeType == ExpressionType.Call) { + var mc = (MethodCallExpression) e; + var methodDeclaringType = mc.Method.DeclaringType; + if (methodDeclaringType.IsGenericType && methodDeclaringType.GetGenericTypeDefinition() == WellKnownTypes.ReadOnlySpanOfT) { + e = mc.Arguments[0]; + } + } return VisitConstant(ExpressionEvaluator.Evaluate(e)); } return base.Visit(e); @@ -410,8 +417,12 @@ protected override SqlExpression VisitMethodCall(MethodCallExpression mc) var arguments = mc.Arguments.SelectToArray(a => Visit(a)); var mi = mc.Method; - if (mc.Object!=null && mc.Object.Type!=mi.ReflectedType) + if (mc.Object!=null && mc.Object.Type!=mi.ReflectedType) { mi = mc.Object.Type.GetMethod(mi.Name, mi.GetParameterTypes()); + } + else if (mi.IsGenericMethod && mi.GetGenericMethodDefinition() == WellKnownMembers.MemoryExtensions.ContainsInReadOnlySpan) { + mi = WellKnownMembers.Enumerable.Contains.CachedMakeGenericMethod(mi.GetGenericArguments()[0]); + } return CompileMember(mi, Visit(mc.Object), arguments); } diff --git a/global.json b/global.json index f721ea586..34dc88acd 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { "allowPrerelease": true, - "version": "9.0.102", + "version": "9.0.200", "rollForward": "latestMajor" } }