Skip to content

Commit

Permalink
Snapshot using comparer even when property is store-generated (#22427)
Browse files Browse the repository at this point in the history
Fixes #21167
  • Loading branch information
ajcvickers committed Sep 8, 2020
1 parent 26c8e1c commit d55c772
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 17 deletions.
12 changes: 3 additions & 9 deletions src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,19 +124,13 @@ protected virtual Expression CreateSnapshotExpression(

if (propertyBase is IProperty property)
{
var storeGeneratedIndex = property.GetStoreGeneratedIndex();
if (storeGeneratedIndex != -1)
{
arguments[i] = CreateReadValueExpression(parameter, property);
continue;
}
arguments[i] = CreateSnapshotValueExpression(CreateReadValueExpression(parameter, property), property);
continue;
}

if (propertyBase.IsShadowProperty())
{
arguments[i] = CreateSnapshotValueExpression(
CreateReadShadowValueExpression(parameter, propertyBase),
propertyBase);
arguments[i] = CreateSnapshotValueExpression(CreateReadShadowValueExpression(parameter, propertyBase), propertyBase);
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.TestUtilities;
using NetTopologySuite;
using NetTopologySuite.Geometries;
using Xunit;

// ReSharper disable InconsistentNaming
Expand Down Expand Up @@ -85,6 +88,8 @@ public BlogContextHiLo(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.UseHiLo();

modelBuilder.Entity<Blog>(
Expand Down Expand Up @@ -147,6 +152,8 @@ public BlogContextDefaultValue(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder
.HasSequence("MySequence")
.StartsAt(0);
Expand All @@ -167,6 +174,8 @@ public BlogContextDefaultValueNoMigrations(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
Expand Down Expand Up @@ -259,6 +268,8 @@ public BlogContextKeyColumnWithDefaultValue(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder
.HasSequence("MySequence")
.StartsAt(77);
Expand Down Expand Up @@ -303,6 +314,8 @@ public BlogContextNoKeyGeneration(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
Expand Down Expand Up @@ -343,6 +356,8 @@ public BlogContextNoKeyGenerationNullableKey(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder
.Entity<NullableKeyBlog>()
.Property(e => e.Id)
Expand All @@ -354,14 +369,22 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
public void Insert_with_non_key_default_value()
{
using var testStore = SqlServerTestStore.CreateInitialized(DatabaseName);

using (var context = new BlogContextNonKeyDefaultValue(testStore.Name))
{
context.Database.EnsureCreatedResiliently();

var blogs = new List<Blog>
{
new Blog { Name = "One Unicorn" },
new Blog { Name = "Two Unicorns", CreatedOn = new DateTime(1969, 8, 3, 0, 10, 0) }
new Blog
{
Name = "Two Unicorns",
CreatedOn = new DateTime(1969, 8, 3, 0, 10, 0),
NeedsConverter = new NeedsConverter(111),
GeometryCollection = GeometryFactory.CreateGeometryCollection(
new Geometry[] { GeometryFactory.CreatePoint(new Coordinate(1, 3)) })
}
};

context.AddRange(blogs);
Expand All @@ -370,30 +393,66 @@ public void Insert_with_non_key_default_value()

Assert.NotEqual(new DateTime(), blogs[0].CreatedOn);
Assert.NotEqual(new DateTime(), blogs[1].CreatedOn);
Assert.Equal(111, blogs[1].NeedsConverter.Value);

var point = ((Point)blogs[1].GeometryCollection.Geometries[0]);
Assert.Equal(1, point.X);
Assert.Equal(3, point.Y);
}

using (var context = new BlogContextNonKeyDefaultValue(testStore.Name))
{
var blogs = context.Blogs.OrderBy(e => e.Name).ToList();
Assert.Equal(3, blogs.Count);

Assert.NotEqual(new DateTime(), blogs[0].CreatedOn);
Assert.Equal(new DateTime(1969, 8, 3, 0, 10, 0), blogs[1].CreatedOn);
Assert.Equal(new DateTime(1974, 8, 3, 0, 10, 0), blogs[2].CreatedOn);

var point1 = ((Point)blogs[1].GeometryCollection.Geometries[0]);
Assert.Equal(1, point1.X);
Assert.Equal(3, point1.Y);

var point2 = ((Point)blogs[2].GeometryCollection.Geometries[0]);
Assert.Equal(1, point2.X);
Assert.Equal(2, point2.Y);

blogs[0].CreatedOn = new DateTime(1973, 9, 3, 0, 10, 0);
blogs[1].Name = "Zwo Unicorns";

blogs[1].Name = "X Unicorns";
blogs[1].NeedsConverter = new NeedsConverter(222);
blogs[1].GeometryCollection.Geometries[0] = GeometryFactory.CreatePoint(new Coordinate(1, 11));

blogs[2].Name = "Y Unicorns";
blogs[2].NeedsConverter = new NeedsConverter(333);
blogs[2].GeometryCollection.Geometries[0] = GeometryFactory.CreatePoint(new Coordinate(1, 22));

context.SaveChanges();
}

using (var context = new BlogContextNonKeyDefaultValue(testStore.Name))
{
var blogs = context.Blogs.OrderBy(e => e.Name).ToList();
Assert.Equal(3, blogs.Count);

Assert.Equal(new DateTime(1969, 8, 3, 0, 10, 0), blogs[1].CreatedOn);
Assert.Equal(new DateTime(1973, 9, 3, 0, 10, 0), blogs[0].CreatedOn);
Assert.Equal(new DateTime(1969, 8, 3, 0, 10, 0), blogs[1].CreatedOn);
Assert.Equal(222, blogs[1].NeedsConverter.Value);
Assert.Equal(new DateTime(1974, 8, 3, 0, 10, 0), blogs[2].CreatedOn);
Assert.Equal(333, blogs[2].NeedsConverter.Value);

var point1 = ((Point)blogs[1].GeometryCollection.Geometries[0]);
Assert.Equal(1, point1.X);
Assert.Equal(11, point1.Y);

var point2 = ((Point)blogs[2].GeometryCollection.Geometries[0]);
Assert.Equal(1, point2.X);
Assert.Equal(22, point2.Y);
}
}

private static readonly GeometryFactory GeometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);

public class BlogContextNonKeyDefaultValue : ContextBase
{
public BlogContextNonKeyDefaultValue(string databaseName)
Expand All @@ -403,11 +462,24 @@ public BlogContextNonKeyDefaultValue(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<Blog>(
b =>
{
b.Property(e => e.CreatedOn)
.HasDefaultValueSql("getdate()");
b.Property(e => e.CreatedOn).HasDefaultValueSql("getdate()");
b.Property(e => e.GeometryCollection).HasDefaultValue(GeometryFactory.CreateGeometryCollection());
b.HasData(
new Blog
{
Id = 9979,
Name = "W Unicorns",
CreatedOn = new DateTime(1974, 8, 3, 0, 10, 0),
NeedsConverter = new NeedsConverter(111),
GeometryCollection = GeometryFactory.CreateGeometryCollection(
new Geometry[] { GeometryFactory.CreatePoint(new Coordinate(1, 2)) })
});
});
}
}
Expand Down Expand Up @@ -464,6 +536,8 @@ public BlogContextNonKeyReadOnlyDefaultValue(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<Blog>()
.Property(e => e.CreatedOn)
.HasDefaultValueSql("getdate()")
Expand Down Expand Up @@ -510,6 +584,8 @@ public BlogContextComputedColumn(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

var property = modelBuilder.Entity<FullNameBlog>()
.Property(e => e.FullName)
.HasComputedColumnSql("FirstName + ' ' + LastName")
Expand Down Expand Up @@ -569,6 +645,8 @@ public BlogContextComputedColumnWithFunction(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<FullNameBlog>()
.Property(e => e.FullName)
.HasComputedColumnSql("[dbo].[GetFullName]([FirstName], [LastName])")
Expand Down Expand Up @@ -686,12 +764,16 @@ public BlogContextClientGuidKey(string databaseName)
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<GuidBlog>(
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<GuidBlog>(
eb =>
{
eb.HasAlternateKey(e => e.NotId);
eb.Property(e => e.NotId).ValueGeneratedOnAdd();
});
}
}

[ConditionalFact]
Expand Down Expand Up @@ -720,7 +802,11 @@ public BlogContextClientGuidNonKey(string databaseName)
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<GuidBlog>().Property(e => e.NotId).ValueGeneratedOnAdd();
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<GuidBlog>().Property(e => e.NotId).ValueGeneratedOnAdd();
}
}

[ConditionalFact]
Expand Down Expand Up @@ -767,6 +853,8 @@ public BlogContextServerGuidKey(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder
.Entity<GuidBlog>(
eb =>
Expand Down Expand Up @@ -859,6 +947,8 @@ public BlogContextSpecifyKeysUsingDefault(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
Expand Down Expand Up @@ -892,6 +982,8 @@ public BlogContextReadOnlySequenceKeyColumnWithDefaultValue(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.HasSequence("MySequence");

modelBuilder
Expand Down Expand Up @@ -1017,6 +1109,8 @@ public BlogContextConcurrencyWithRowversion(string databaseName)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<ConcurrentBlog>()
.Property(e => e.Timestamp)
.ValueGeneratedOnAddOrUpdate()
Expand All @@ -1029,9 +1123,25 @@ public class Blog
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedOn { get; set; }
public NeedsConverter NeedsConverter { get; set; }
public GeometryCollection GeometryCollection { get; set; }
public int? OtherId { get; set; }
}

public class NeedsConverter
{
public NeedsConverter(int value)
=> Value = value;

public int Value { get; }

public override bool Equals(object obj)
=> throw new InvalidOperationException();

public override int GetHashCode()
=> throw new InvalidOperationException();
}

public class NullableKeyBlog
{
public int? Id { get; set; }
Expand Down Expand Up @@ -1076,12 +1186,26 @@ protected ContextBase(string databaseName)
public DbSet<GuidBlog> GuidBlogs { get; set; }
public DbSet<ConcurrentBlog> ConcurrentBlogs { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(e => e.NeedsConverter)
.HasConversion(
v => v.Value,
v => new NeedsConverter(v),
new ValueComparer<NeedsConverter>(
(l, r) => l.Value == r.Value,
v => v.Value.GetHashCode(),
v => new NeedsConverter(v.Value)))
.HasDefaultValue(new NeedsConverter(999));
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.EnableServiceProviderCaching(false)
.UseSqlServer(
SqlServerTestStore.CreateConnectionString(_databaseName),
b => b.ApplyConfiguration());
b => b.UseNetTopologySuite().ApplyConfiguration());
}
}
}

0 comments on commit d55c772

Please sign in to comment.