Open ajcvickers opened 6 years ago
Note that #12434 and #12436 should be implemented first.
There appears to be a bug in the way RowVersion/Timestamp fields are converted from byte[]
to ulong
.
I have two models, both of which have Timestamp properties:
public class First
{
public Guid ID { get; set; }
public ulong Timestamp { get; set; }
}
public class Second
{
public Guid Id { get; set; }
public ulong Timestamp { get; set; }
public Guid? OtherID { get; set; }
public First Other { get; set; }
}
that are mapped as RowVersion fields:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<First>()
.Property(e => e.Timestamp)
.HasColumnType(“RowVersion”)
.IsRowVersion();
modelBuilder.Entity<Second>()
.Property(e => e.Timestamp)
.HasColumnType(“RowVersion”)
.IsRowVersion();
}
Note that OtherID
on the Second
model is a nullable property.
If I run the following query:
dbContext.Seconds.Include(s => Other).ToList();
as long as the OtherID
is not NULL, everything works fine. But when it's set to NULL, apparently the Other
referenced entity's Timestamp
property is still being converted for some reason (or at least an attempt is made to convert it).
Because that's NULL, an exception is thrown from the NumberToBytesConverter
:
Unhandled Exception: System.InvalidOperationException: An exception occurred while reading a database value for property 'First.Timestamp'. See the inner exception for more information. ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Microsoft.EntityFrameworkCore.Storage.ValueConversion.NumberToBytesConverter`1.ReverseLong(Byte[] bytes)
at lambda_method(Closure , DbDataReader )
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Metadata.Internal.EntityMaterializerSource.ThrowReadValueException[TValue](Exception exception, Object value, IPropertyBase property)
at lambda_method(Closure , DbDataReader )
at Microsoft.EntityFrameworkCore.Storage.Internal.TypedRelationalValueBufferFactory.Create(DbDataReader dataReader)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
at System.Linq.Enumerable.SelectEnumerableIterator`2.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider._TrackEntities[TOut,TIn](IEnumerable`1 results, QueryContext queryContext, IList`1 entityTrackingInfos, IList`1 entityAccessors)+MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
at System.Collections.Generic.List`1.AddEnumerable(IEnumerable`1 enumerable)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at EFConcurrencyTest.Program.Main(String[] args) in <project_main>
If I understand this correctly, the converter is not handling NULL values properly?
@patrikrazem This looks like a duplicate of issue #12518
You're absolutely right, I must've missed that issue.
Also recommend using ulong?
for rowversion properties in Docs
Because mapping to ulong with conversion is a nicer experience that mapping to byte[]. See #5936