-
Notifications
You must be signed in to change notification settings - Fork 352
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes #2293: Enable DateOnly and TimeOnly #3078
Conversation
Can write the 'DateOnly' and 'TimeOnly' Can read the 'DateOnly' and 'TimeOnly'
src/Microsoft.OData.Client/Serialization/PrimitiveXmlConverter.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.OData.Client/Serialization/PrimitiveXmlConverter.cs
Outdated
Show resolved
Hide resolved
@xuzhg I left a few comments, but by and large this looks great, and I'm really grateful to see this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I confess that while reading this PR, it stuck out to me how many different places that need updating to introduce a new type. This feels less than ideal to me.
Of course, this has nothing to do with the changes themselves but with the overall design.
Added a few minor comments and suggestions, but don't see any major problems here.
test/FunctionalTests/Microsoft.OData.Core.Tests/Json/JsonWriterBaseTests.cs
Outdated
Show resolved
Hide resolved
@@ -223,6 +224,11 @@ private static string FormatRawLiteral(object value) | |||
return value.ToString(); | |||
} | |||
|
|||
if (value is DateOnly dateOnly) | |||
{ | |||
return ((Date)dateOnly).ToString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder whether it's necessary to cast to Date
here? Could we consider creating Date-to-string helper function that could be used to ensure consistency for both Date
and DateOnly
but could allow us to work with DateOnly
without having to cast to Date
? I think if DateOnly
is used often or the preferred choice in the future, we should consider having first-class support for it and avoid the overhead of casting to Date
when possible. If that's a lot of work, it could be done in a follow-up PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the next breaking change version (9 version), we should remove 'Date' 'TimeOfDay' and use 'DateOnly' and 'TimeOnly' types introduced in .NET.
In current 8 version, I try to avoid breaking change. And most important, we should make sure to get the same 'literal' string no matter whether customers are using 'Date' or 'DateOnly'.
DateOnly has several 'ToString()' overloads, the string literal varys along with the formatter provider. 'Cast' to Date then call 'ToString' on 'Date' is a 'center' method and make sure we get the same literal string no matter what type is. And to call 'ToString()' is a straightforward. There's no need to create a helper method to wrapper 'ToString()' again. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was curious about the potential overhead of casting to Edm.Date
so I ran some tests to measure the ToString()
scenario. To my surprise, casting to Edm.Date
then call ToString()
(i.e. ((Date)dateOnly).ToString()
appears to be faster than dateOnly.ToString("yyyy-MM-dd", InvariantCulture)
.
This issue appears to be specific case of DateOnly.ToString(format, provider)
overload which verifies that format is a valid date-only format, and this verification happens in O(n). You can bypass this overhead by converting the DateOnly
to DateTime
then calling DateTime.ToString("yyyy-MM-dd", InvariantCulture)
. This happens to be faster than casting to Edm.Date
.
Here's the benchmark code.
This was meant to verify whether there's an actual overhead of casting DateOnly
to Edm.Date
and that we can avoid that perf overhead by handling DateOnly
directly
@@ -233,6 +239,11 @@ private static string FormatRawLiteral(object value) | |||
return value.ToString(); | |||
} | |||
|
|||
if (value is TimeOnly timeOnly) | |||
{ | |||
return ((TimeOfDay)timeOnly).ToString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar concerns as https://github.com/OData/odata.net/pull/3078/files#r1792817270 on whether we can avoid casting to TimeOfDay
and handle TimeOnly
directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally looks good to me. I would recommend creating a follow-up item to investigate whether we can get better performance by handling DateOnly
and TimeOnly
directly in OData.Core instead of casting to and from Edm.Date
and Edm.TimeOfDay
respectively.
What does the release schedule for merged PR's look like? Can we expect this change to be included in the versions distributed via NuGet any time soon? Or is this part of a periodic release with a longer release window? |
I think we will have a new version on nuget.org soon. We will try our best to unblock any customer. |
Issues
This pull request fixes #2293.
Description
OData.Spec defines the following two primitive types:
![image](https://private-user-images.githubusercontent.com/9426627/373341813-58a97934-be94-4154-a610-2841f4b1b824.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkyNDE2NzMsIm5iZiI6MTczOTI0MTM3MywicGF0aCI6Ii85NDI2NjI3LzM3MzM0MTgxMy01OGE5NzkzNC1iZTk0LTQxNTQtYTYxMC0yODQxZjRiMWI4MjQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxMSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTFUMDIzNjEzWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9Mjg1OWNlY2I5YmM4Njk2N2Q2ZGU4ZGExODkzMWYyYTNhNThhNjlkMDBhMDBmNjM5ODY1YjAzYWRkOWE4MzUxMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.OCuUR1aXbA6wbpuAmlG40MGoSmSiDej68xo7Fae7LaI)
From OData model perspective, it only knows
Edm.Date
andEdm.TimeOfDay
.We'd resolve the mapping between the Edm types and C# types from the real value.
OData library maps 'Edm.Date' to 'Microsoft.OData.Edm.Date' struct and 'Edm.TimeOfDay' to 'Microsoft.OData.Edm.TimeOfDay' struct.
However, neither 'Date' type nor 'TimeOfDay' is supported in database side.
Now since .NET 6, two new primitive types have introduced into the 'System" namespace as:
System.TimeOnly
System.DateOnly
They are widely used in modern database side and EF core supports them. See at: dotnet/efcore#24507
and Here: https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/breaking-changes
At OData side, we should support those two types as well.
At OData.Edm side, typically we don't need to change anything. Because it only knows the 'Edm.Date' and 'Edm.TimeOfDay' primitive types. But for conversion, we'd update 'Date' and 'TimeOfDay' struct type to support convert to 'System.DateOnly' and 'System.TimeOnly' respectively, implicitly.
At OData.Core side, we'd support to write the 'DateOnly' and 'TimeOnly' values, same as 'Date' and 'TimeOfDay' respectively.
For reading, suppose we have a property at model side as:
So, if ODL reads the value of 'ValidDate' property, we can continue to read it as 'Date' instance and it should be able to convert it to 'System.DateOnly' implicitly.
At OData.Client side, we should support to create the property using the correct C# types (Microsoft.OData.Edm.Date, or System.DateOnly) during code generation. I'd suggest to add a flag/configuration for the OData Connected service to switch between them. This part is not included in this PR.
Checklist (Uncheck if it is not completed)
Additional work necessary
If documentation update is needed, please add "Docs Needed" label to the issue and provide details about the required document change in the issue.