Skip to content

Commit

Permalink
Fix: dotnet#7048 - EF Core 1.1 .ToString() translation causes exception
Browse files Browse the repository at this point in the history
Adding bad data error handling logic to materialization introduced the possibility
of hitting a known expression compiler limitation (as described here: dotnet/corefx#13126).

This change works around the limitation by moving the read-value try-catch to a helper method, thus we no
longer insert a try-catch directly into the output ET.
  • Loading branch information
anpete committed Nov 21, 2016
1 parent 539c9e6 commit dd44082
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ public virtual void Include_multiple_one_to_one_and_one_to_many()
}
}

[ConditionalFact]
public virtual void ToString_guid_property_projection()
{
using (var context = CreateContext())
{
var query = context.Tags.Select(ct => new { A = ct.GearNickName, B = ct.Id.ToString() });
var result = query.ToList();

Assert.Equal(6, result.Count);
}
}

[ConditionalFact]
public virtual void Include_multiple_one_to_one_and_one_to_many_self_reference()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,34 +29,42 @@ private static readonly MethodInfo _readValue
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public virtual Expression CreateReadValueExpression(
Expression valueBuffer,
Type type,
Expression valueBuffer,
Type type,
int index,
IProperty property = null)
=> Expression.Call(
_tryReadValueMethod.MakeGenericMethod(type),
valueBuffer,
Expression.Constant(index),
Expression.Constant(property, typeof(IPropertyBase)));

private static readonly MethodInfo _tryReadValueMethod
= typeof(EntityMaterializerSource).GetTypeInfo()
.GetDeclaredMethod(nameof(TryReadValue));

private static TValue TryReadValue<TValue>(
ValueBuffer valueBuffer,
int index,
IProperty property = null)
IPropertyBase property = null)
{
var readValueExpression
= Expression.Convert(CreateReadValueCallExpression(valueBuffer, index), type);

var exceptionParameter
= Expression.Parameter(typeof(Exception), "e");

var catchBlock
= Expression
.Catch(exceptionParameter,
Expression.Call(
_createReadValueException.MakeGenericMethod(readValueExpression.Type),
exceptionParameter,
CreateReadValueCallExpression(valueBuffer, index),
Expression.Constant(property, typeof(IPropertyBase))));

return Expression.TryCatch(readValueExpression, catchBlock);
}
object untypedValue = null;

private static readonly MethodInfo _createReadValueException
= typeof(EntityMaterializerSource).GetTypeInfo()
.GetDeclaredMethod(nameof(ThrowReadValueException));
try
{
untypedValue = valueBuffer[index];

private static TValue ThrowReadValueException<TValue>(
return (TValue)untypedValue;
}
catch (Exception e)
{
ThrowReadValueException<TValue>(e, untypedValue, property);
}

return default(TValue);
}

private static void ThrowReadValueException<TValue>(
Exception exception, object value, IPropertyBase property = null)
{
var expectedType = typeof(TValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,26 @@ ORDER BY [o].[CustomerID]
materializer: (ValueBuffer valueBuffer) =>
{
var3 = new Order()
var3.<OrderID>k__BackingField = try { (int) object valueBuffer.get_Item(0) } catch (Exception) { ... }
var3.<CustomerID>k__BackingField = try { (string) object valueBuffer.get_Item(1) } catch (Exception) { ... }
var3.<EmployeeID>k__BackingField = try { (Nullable<int>) object valueBuffer.get_Item(2) } catch (Exception) { ... }
var3.<OrderDate>k__BackingField = try { (Nullable<DateTime>) object valueBuffer.get_Item(3) } catch (Exception) { ... }
var3.<OrderID>k__BackingField = int TryReadValue(
valueBuffer: valueBuffer,
index: 0,
property: OrderID
)
var3.<CustomerID>k__BackingField = string TryReadValue(
valueBuffer: valueBuffer,
index: 1,
property: CustomerID
)
var3.<EmployeeID>k__BackingField = Nullable<int> TryReadValue(
valueBuffer: valueBuffer,
index: 2,
property: EmployeeID
)
var3.<OrderDate>k__BackingField = Nullable<DateTime> TryReadValue(
valueBuffer: valueBuffer,
index: 3,
property: OrderDate
)
return instance
}
)
Expand Down

0 comments on commit dd44082

Please sign in to comment.