Skip to content
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

Reverse engineering rowversion/timestamp on SQL Server should generate ulong property #12435

Open
Tracked by #22948
ajcvickers opened this issue Jun 20, 2018 · 5 comments

Comments

@ajcvickers
Copy link
Member

Because mapping to ulong with conversion is a nicer experience that mapping to byte[]. See #5936

@ajcvickers ajcvickers added this to the Backlog milestone Jun 27, 2018
@ajcvickers ajcvickers added the help wanted This issue involves technologies where we are not experts. Expert help would be appreciated. label Jun 27, 2018
@ajcvickers
Copy link
Member Author

Note that #12434 and #12436 should be implemented first.

@patrikrazem
Copy link

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?

@ajcvickers
Copy link
Member Author

@patrikrazem This looks like a duplicate of issue #12518

@patrikrazem
Copy link

You're absolutely right, I must've missed that issue.

@divega divega added good first issue This issue should be relatively straightforward to fix. help wanted This issue involves technologies where we are not experts. Expert help would be appreciated. and removed help wanted This issue involves technologies where we are not experts. Expert help would be appreciated. good first issue This issue should be relatively straightforward to fix. labels May 31, 2019
@ajcvickers ajcvickers added good first issue This issue should be relatively straightforward to fix. and removed help wanted This issue involves technologies where we are not experts. Expert help would be appreciated. labels Aug 5, 2019
@ajcvickers ajcvickers removed the good first issue This issue should be relatively straightforward to fix. label Aug 30, 2019
@AndriySvyryd
Copy link
Member

Also recommend using ulong? for rowversion properties in Docs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants