Skip to content

Commit 29e8218

Browse files
committed
Lift try..catch out of an expression and replace with a temporary variable
Fixes dotnet#34393
1 parent a0d6550 commit 29e8218

4 files changed

+62
-24
lines changed

src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs

+25-2
Original file line numberDiff line numberDiff line change
@@ -2039,6 +2039,28 @@ LiteralExpressionSyntax literal when literal.IsKind(SyntaxKind.NullLiteralExpres
20392039
};
20402040
}
20412041

2042+
private Expression LiftTryExpression(TryExpression tryExpression)
2043+
{
2044+
using var _ = ChangeContext(ExpressionContext.Statement);
2045+
var name = UniquifyVariableName("temp");
2046+
var variable = Expression.Parameter(tryExpression.Type, name);
2047+
var newBody = Expression.Assign(variable, tryExpression.Body);
2048+
var newTry = tryExpression.Update(newBody, tryExpression.Handlers, tryExpression.Finally, tryExpression.Fault);
2049+
2050+
_liftedState.Statements.Add(GenerateVarDeclaration(name, DefaultExpression(Generate(variable.Type))));
2051+
2052+
var re = Translate<TryStatementSyntax>(newTry);
2053+
_liftedState.Statements.Add(re);
2054+
_liftedState.VariableNames.Add(name);
2055+
_liftedState.Variables[variable] = name;
2056+
2057+
var currentStack = _stack.Peek();
2058+
currentStack.Variables[variable] = name;
2059+
currentStack.VariableNames.Add(name);
2060+
2061+
return variable;
2062+
}
2063+
20422064
/// <inheritdoc />
20432065
protected override Expression VisitNewArray(NewArrayExpression newArray)
20442066
{
@@ -2414,8 +2436,9 @@ protected override Expression VisitTry(TryExpression tryNode)
24142436

24152437
case ExpressionContext.Expression:
24162438
case ExpressionContext.ExpressionLambda:
2417-
throw new NotImplementedException();
2418-
2439+
var liftedVariable = LiftTryExpression(tryNode);
2440+
Result = Translate(liftedVariable);
2441+
return tryNode;
24192442
default:
24202443
throw new ArgumentOutOfRangeException();
24212444
}

src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.ClientMethods.cs

+8-7
Original file line numberDiff line numberDiff line change
@@ -126,16 +126,17 @@ public static TValue ThrowReadValueException<TValue>(
126126
throw new InvalidOperationException(message, exception);
127127
}
128128

129+
/// <summary>
130+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
131+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
132+
/// any release. You should only use it directly in your code with extreme caution and knowing that
133+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
134+
/// </summary>
129135
[MethodImpl(MethodImplOptions.AggressiveInlining)]
130-
private static TValue ThrowExtractJsonPropertyException<TValue>(Exception exception, IProperty property)
131-
{
132-
var entityType = property.DeclaringType.DisplayName();
133-
var propertyName = property.Name;
134-
135-
throw new InvalidOperationException(
136+
[EntityFrameworkInternal]
137+
public static TValue ThrowExtractJsonPropertyException<TValue>(Exception exception, string entityType, string propertyName) => throw new InvalidOperationException(
136138
RelationalStrings.JsonErrorExtractingJsonProperty(entityType, propertyName),
137139
exception);
138-
}
139140

140141
/// <summary>
141142
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to

src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs

+28-14
Original file line numberDiff line numberDiff line change
@@ -2863,20 +2863,33 @@ Expression valueExpression
28632863
&& !buffering)
28642864
{
28652865
var exceptionParameter = Parameter(typeof(Exception), name: "e");
2866-
2867-
var catchBlock = Catch(
2868-
exceptionParameter,
2869-
Call(
2870-
ThrowReadValueExceptionMethod.MakeGenericMethod(valueExpression.Type),
2866+
CatchBlock? catchBlock = null;
2867+
if (property != null)
2868+
{
2869+
catchBlock = Catch(
28712870
exceptionParameter,
2872-
Call(dbDataReader, GetFieldValueMethod.MakeGenericMethod(typeof(object)), indexExpression),
2873-
Constant(valueExpression.Type.MakeNullable(nullable), typeof(Type)),
2874-
_parentVisitor.Dependencies.LiftableConstantFactory.CreateLiftableConstant(
2875-
property,
2876-
LiftableConstantExpressionHelpers.BuildMemberAccessLambdaForProperty(property),
2877-
property + "Property",
2878-
typeof(IPropertyBase))));
2879-
2871+
Call(
2872+
ThrowReadValueExceptionMethod.MakeGenericMethod(valueExpression.Type),
2873+
exceptionParameter,
2874+
Call(dbDataReader, GetFieldValueMethod.MakeGenericMethod(typeof(object)), indexExpression),
2875+
Constant(valueExpression.Type.MakeNullable(nullable)),
2876+
_parentVisitor.Dependencies.LiftableConstantFactory.CreateLiftableConstant(
2877+
property,
2878+
LiftableConstantExpressionHelpers.BuildMemberAccessLambdaForProperty(property),
2879+
property.Name + "Property",
2880+
typeof(IPropertyBase))));
2881+
}
2882+
else
2883+
{
2884+
catchBlock = Catch(
2885+
exceptionParameter,
2886+
Call(
2887+
ThrowReadValueExceptionMethod.MakeGenericMethod(valueExpression.Type),
2888+
exceptionParameter,
2889+
Call(dbDataReader, GetFieldValueMethod.MakeGenericMethod(typeof(object)), indexExpression),
2890+
Constant(valueExpression.Type.MakeNullable(nullable)),
2891+
Constant(null,typeof(IPropertyBase))));
2892+
}
28802893
valueExpression = TryCatch(valueExpression, catchBlock);
28812894
}
28822895

@@ -3005,7 +3018,8 @@ private Expression CreateReadJsonPropertyValueExpression(
30053018
Call(
30063019
ThrowExtractJsonPropertyExceptionMethod.MakeGenericMethod(resultExpression.Type),
30073020
exceptionParameter,
3008-
Constant(property, typeof(IProperty))));
3021+
Constant(property.DeclaringType.DisplayName(), typeof(string)),
3022+
Constant(property.Name, typeof(string))));
30093023

30103024
resultExpression = TryCatch(resultExpression, catchBlock);
30113025
}

test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledQuerySqlServerTest.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2091,7 +2091,7 @@ public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder build
20912091
// TODO: Figure out if there's a nice way to continue using the retrying strategy
20922092
var sqlServerOptionsBuilder = new SqlServerDbContextOptionsBuilder(builder);
20932093
sqlServerOptionsBuilder.ExecutionStrategy(d => new NonRetryingExecutionStrategy(d));
2094-
return builder;
2094+
return builder.EnableDetailedErrors();
20952095
}
20962096

20972097
public override PrecompiledQueryTestHelpers PrecompiledQueryTestHelpers

0 commit comments

Comments
 (0)