From f953826c421ef0c10d851b38a02004e298654de0 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Mon, 7 Mar 2022 21:41:01 -0800 Subject: [PATCH] Fix Issue 224 --- .../Orm/Internals/CompiledQueryRunner.cs | 40 +++++++++++++++---- Orm/Xtensive.Orm/Reflection/WellKnownTypes.cs | 4 +- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Internals/CompiledQueryRunner.cs b/Orm/Xtensive.Orm/Orm/Internals/CompiledQueryRunner.cs index bc036269a3..648c513d9c 100644 --- a/Orm/Xtensive.Orm/Orm/Internals/CompiledQueryRunner.cs +++ b/Orm/Xtensive.Orm/Orm/Internals/CompiledQueryRunner.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2012-2021 Xtensive LLC. +// Copyright (C) 2012-2022 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov @@ -7,6 +7,7 @@ using System; using System.Linq; using System.Linq.Expressions; +using System.Reflection; using System.Threading; using System.Threading.Tasks; using Xtensive.Caching; @@ -19,6 +20,8 @@ namespace Xtensive.Orm.Internals { internal class CompiledQueryRunner { + private static readonly Func FieldIsSimple = fieldInfo => TypeIsSimple(fieldInfo.FieldType); + private readonly Domain domain; private readonly Session session; private readonly QueryEndpoint endpoint; @@ -108,7 +111,7 @@ private DelayedQuery CreateDelayedSequenceQuery( private ParameterizedQuery GetScalarQuery( Func query, bool executeAsSideEffect, out TResult result) { - AllocateParameterAndReplacer(); + var cacheable = AllocateParameterAndReplacer(); var parameterContext = new ParameterContext(outerContext); parameterContext.SetValue(queryParameter, queryTarget); @@ -123,7 +126,9 @@ private ParameterizedQuery GetScalarQuery( throw new NotSupportedException(Strings.ExNonLinqCallsAreNotSupportedWithinQueryExecuteDelayed); } - PutCachedQuery(parameterizedQuery); + if (cacheable) { + PutCachedQuery(parameterizedQuery); + } return parameterizedQuery; } @@ -135,7 +140,7 @@ private ParameterizedQuery GetSequenceQuery( return parameterizedQuery; } - AllocateParameterAndReplacer(); + var cacheable = AllocateParameterAndReplacer(); var scope = new CompiledQueryProcessingScope(queryParameter, queryParameterReplacer); using (scope.Enter()) { var result = query.Invoke(endpoint); @@ -143,16 +148,18 @@ private ParameterizedQuery GetSequenceQuery( parameterizedQuery = (ParameterizedQuery) translatedQuery; } - PutCachedQuery(parameterizedQuery); + if (cacheable) { + PutCachedQuery(parameterizedQuery); + } return parameterizedQuery; } - private void AllocateParameterAndReplacer() + private bool AllocateParameterAndReplacer() { if (queryTarget == null) { queryParameter = null; queryParameterReplacer = new ExtendedExpressionReplacer(e => e); - return; + return true; } var closureType = queryTarget.GetType(); @@ -192,6 +199,25 @@ private void AllocateParameterAndReplacer() } return null; }); + + return !closureType.Name.Contains("<>c__DisplayClass") // 'DisplayClass' is generated class for captured objects + || closureType.GetFields().All(FieldIsSimple); + } + + private static bool TypeIsSimple(Type type) + { + var typeInfo = type.GetTypeInfo(); + if (typeInfo.IsGenericType) { + var genericDef = typeInfo.GetGenericTypeDefinition(); + return (genericDef == WellKnownTypes.NullableOfT || genericDef.IsAssignableTo(WellKnownTypes.IReadOnlyList)) + && TypeIsSimple(typeInfo.GetGenericArguments()[0]); + } + else if (typeInfo.IsArray) { + return TypeIsSimple(typeInfo.GetElementType()); + } + else { + return typeInfo.IsPrimitive || typeInfo.IsEnum || type == WellKnownTypes.String || type == WellKnownTypes.Decimal; + } } private ParameterizedQuery GetCachedQuery() => diff --git a/Orm/Xtensive.Orm/Reflection/WellKnownTypes.cs b/Orm/Xtensive.Orm/Reflection/WellKnownTypes.cs index d8378b5a7d..d8dcdecb9a 100644 --- a/Orm/Xtensive.Orm/Reflection/WellKnownTypes.cs +++ b/Orm/Xtensive.Orm/Reflection/WellKnownTypes.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2020 Xtensive LLC. +// Copyright (C) 2020-2022 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. using System; +using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -73,6 +74,7 @@ internal static class WellKnownTypes public static readonly Type ByteArray = typeof(byte[]); public static readonly Type ObjectArray = typeof(object[]); + public static readonly Type IReadOnlyList = typeof(IReadOnlyList<>); public static readonly Type DefaultMemberAttribute = typeof(DefaultMemberAttribute); }