Fix date() and time() function translation (#792)#1407
Fix date() and time() function translation (#792)#1407jamerst wants to merge 4 commits intoOData:mainfrom
Conversation
|
@microsoft-github-policy-service agree |
| PropertyInfo property = type.GetProperty(nameof(DateTime.Date)); | ||
|
|
||
| Expression propertyAccessExpr = ExpressionBinderHelper.MakePropertyAccess(property, arguments[0], QuerySettings); | ||
| return ExpressionBinderHelper.CreateFunctionCallWithNullPropagation(propertyAccessExpr, arguments, QuerySettings); |
There was a problem hiding this comment.
Thanks for this fix.
Just to confirm..
Will this change break for users still using older versions of Entity Framework other than EF6? Why not add a condition to ensure it supports older versions of EF.
There was a problem hiding this comment.
@WanjohiSammy Added handling for EF6 (just falls back to the previous behaviour of returning the source).
This required moving the IsClassicEF method and ClassicEF properties from TransformationBinderBase up to ExpressionBinderBase.
| PropertyInfo property = type.GetProperty(nameof(DateTime.TimeOfDay)); | ||
|
|
||
| Expression propertyAccessExpr = ExpressionBinderHelper.MakePropertyAccess(property, arguments[0], QuerySettings); | ||
| return ExpressionBinderHelper.CreateFunctionCallWithNullPropagation(propertyAccessExpr, arguments, QuerySettings); |
There was a problem hiding this comment.
Same here:
Older versions might not support new features from EF6. Adding a condition ensures compatibility.
There was a problem hiding this comment.
Resolved same as in https://github.com/OData/AspNetCoreOData/pull/1407/files#r1944232224
| PropertyInfo property = type.GetProperty(nameof(DateTime.Date)); | ||
|
|
||
| Expression propertyAccessExpr = ExpressionBinderHelper.MakePropertyAccess(property, arguments[0], context.QuerySettings); | ||
| return ExpressionBinderHelper.CreateFunctionCallWithNullPropagation(propertyAccessExpr, arguments, context.QuerySettings); |
There was a problem hiding this comment.
There was a problem hiding this comment.
Is it possible to tell if the query provider is EF6 from here?
The only place I can find that checks if it is EF6 is in TransformationBinderBase, and it uses the type of IQueryable.Provider to do so.
That would probably work for the translation in ExpressionBinderBase since TransformationBinderBase derives from it, but QueryBinder isn't exposed to the queryable at any point?
There was a problem hiding this comment.
@WanjohiSammy Added handling for EF6 here too, same as Resolved as in https://github.com/OData/AspNetCoreOData/pull/1407/files#r1944232224.
As previously mentioned QueryBinder wasn't exposed to the queryable at any point, to get around this an IsClassicEF property has been added to QueryBinderContext and a new constructor for it accepting IQueryProvider added.
This has been added as an additional constructor to preserve the public API, the new one could be changed to be internal if wanted but leaving it as public probably makes the most sense. The new constructor should now be in use everywhere that requires it.
| new[] {"$orderby=NullableTimeOfDay desc", "5 > 4 > 2 > 1 > 3"}, | ||
|
|
||
| new[] {"$orderby=date(SameDayDateTime), Id desc", "5 > 4 > 3 > 2 > 1"}, | ||
| new[] {"$orderby=date(SameDayNullableDateTime), Id desc", "4 > 2 > 5 > 3 > 1"}, |
There was a problem hiding this comment.
These tests are for the in-memory queryable provider, there are a couple of tests for EF too below
| return arguments[0]; | ||
|
|
||
| // EF6 and earlier don't support translating the Date property, so just return the original value | ||
| if (ClassicEF) |
There was a problem hiding this comment.
The new QueryBinder and QueryBinderContext were designed to remove the tight coupling with IQueryable that was present in ExpressionBinderBase and the older Binders.
Can you add a Custom FilterBinder and override this method with your custom implementation? That's a cleaner solution.
Reference https://devblogs.microsoft.com/odata/customizing-filter-for-spatial-data-in-asp-net-core-odata-8/#customizing-filterbinder
There was a problem hiding this comment.
That would be the ideal solution, however that doesn't work for all operators. Aggregation and compute operations still use ExpressionBinderBase so can't be customised (unless that has changed since this PR was opened?)
Fix #792 -
date()function not being translated. Also fixes similar issue oftime()function not being translated.The comments previously implied that the
DateandTimeOfDayproperties ofDateTimeandDateTimeOffsetwere not supported by EF, but this is not the case with EF Core (see function mappings documentation).The translation has been updated to use these properties for the functions so that they work correctly. Test cases have been added for when they are used in $orderby specifically.
Note that this issue was not present in most circumstances when the
date()function was used in $filter due to the type conversion used when dealing with Date types in binary expressions resulting in dates being compared via an integer representation instead:AspNetCoreOData/src/Microsoft.AspNetCore.OData/Query/Expressions/ExpressionBinderHelper.cs
Lines 425 to 441 in c860cdc
This won't work with EF6 as it doesn't support translating the
Dateproperty. Not sure if this is a problem, does this library even officially support EF6? Attempting to work around it feels somewhat out of scope.