SqlClient: LegacyRowVersionNullBehavior causes InvalidCastException when using SqlDataReader.GetFieldValue[T]
Describe the bug
I updated my project, which uses EF Core 5.0.8, to use the latest version SqlClient, 3.0.0, and got an InvalidCastException exception. Turning off SqlServerDbContextOptionsBuilder.EnableRetryOnFailure()
prevents the error, but I need it on.
Investigating further, the issue seems to come from SqlDataReader.GetFieldValue[T](Int32 i)
.
Exception message: Unable to cast object of type 'System.DBNull' to type 'System.Byte[]'.
Stack trace:
System.InvalidCastException: Unable to cast object of type 'System.DBNull' to type 'System.Byte[]'.
at Microsoft.Data.SqlClient.SqlDataReader.GetFieldValueFromSqlBufferInternal[T](SqlBuffer data, _SqlMetaData metaData)
at Microsoft.Data.SqlClient.SqlDataReader.GetFieldValueInternal[T](Int32 i)
at Microsoft.Data.SqlClient.SqlDataReader.GetFieldValue[T](Int32 i)
To reproduce
I’ve recreated the issue in a repo: https://github.com/andygjp/NullRowVersionIssue
Expected behavior
It should not throw an exception - the GetFieldValueFromSqlBufferInternal() function needs to have the same behaviour as TryReadColumnInternal(Int32, Bool), ie respect LocalAppContextSwitches.LegacyRowVersionNullBehavior
Further technical details
dotnet --info
.NET SDK (reflecting any global.json):
Version: 5.0.204
Commit: 84d1fe1bb7
Runtime Environment:
OS Name: fedora
OS Version: 34
OS Platform: Linux
RID: fedora.34-x64
Base Path: /usr/lib64/dotnet/sdk/5.0.204/
Host (useful for support):
Version: 5.0.7
Commit: 556582d964
.NET SDKs installed:
3.1.116 [/usr/lib64/dotnet/sdk]
5.0.204 [/usr/lib64/dotnet/sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 3.1.16 [/usr/lib64/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.7 [/usr/lib64/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.16 [/usr/lib64/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.7 [/usr/lib64/dotnet/shared/Microsoft.NETCore.App]
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 2
- Comments: 15 (12 by maintainers)
Yes. Sometimes I find that it’s the cleanest way to express things. This approach doesn’t duplicate work and clearly separates decision and action. I could break the two action blocks into location functions or dedicated functions but it feels wasteful doing all that work setting up a stackframe and pushing/popping args for such small reasons.
I intend to look at it so you can assign it to me.