Skip to content

Commit

Permalink
Be more resilient when using the model from the model snapshot
Browse files Browse the repository at this point in the history
Fixes #17145 but see also #17205

The fix here allows the state manager to work, which is required when the model snapshot has model data in it.
  • Loading branch information
ajcvickers committed Aug 16, 2019
1 parent 881790b commit ef1b09c
Show file tree
Hide file tree
Showing 13 changed files with 50 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/EFCore.InMemory/Storage/Internal/InMemoryTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ private static List<ValueComparer> GetStructuralComparers(IEnumerable<IProperty>
=> properties.Select(GetStructuralComparer).ToList();

private static ValueComparer GetStructuralComparer(IProperty p)
=> p.GetStructuralValueComparer() ?? p.GetTypeMapping().StructuralComparer;
=> p.GetStructuralValueComparer() ?? p.FindTypeMapping()?.StructuralComparer;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
3 changes: 2 additions & 1 deletion src/EFCore.Relational/Infrastructure/ModelSnapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

namespace Microsoft.EntityFrameworkCore.Infrastructure
{
Expand All @@ -16,7 +17,7 @@ public abstract class ModelSnapshot

private IMutableModel CreateModel()
{
var modelBuilder = new ModelBuilder(new ConventionSet());
var modelBuilder = new ModelBuilder(new Model());
BuildModel(modelBuilder);

return modelBuilder.Model;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1814,8 +1814,8 @@ protected virtual void DiffData(
var targetValue = entry.GetCurrentValue(targetProperty);
var comparer = targetProperty.GetValueComparer() ??
sourceProperty.GetValueComparer() ??
targetProperty.GetTypeMapping().Comparer ??
sourceProperty.GetTypeMapping().Comparer;
targetProperty.FindTypeMapping()?.Comparer ??
sourceProperty.FindTypeMapping()?.Comparer;

var modelValuesChanged
= sourceProperty.ClrType.UnwrapNullableType() == targetProperty.ClrType.UnwrapNullableType()
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/ChangeTracking/Internal/ChangeDetector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ private void DetectKeyChange(InternalEntityEntry entry, IProperty property)
var currentValue = entry[property];

var comparer = property.GetKeyValueComparer()
?? property.GetTypeMapping().KeyComparer;
?? property.FindTypeMapping()?.KeyComparer;

// Note that mutation of a byte[] key is not supported or detected, but two different instances
// of byte[] with the same content must be detected as equal.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ protected virtual bool TryCreateFromEntry(
/// </summary>
protected static IEqualityComparer<object[]> CreateEqualityComparer([NotNull] IReadOnlyList<IProperty> properties)
{
var comparers = properties.Select(p => p.GetKeyValueComparer() ?? p.GetTypeMapping().KeyComparer).ToList();
var comparers = properties.Select(p => p.GetKeyValueComparer() ?? p.FindTypeMapping()?.KeyComparer).ToList();

return comparers.All(c => c != null)
? new CompositeCustomComparer(comparers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public SimplePrincipalKeyValueFactory([NotNull] IProperty property)
_propertyAccessors = _property.GetPropertyAccessors();

var comparer = property.GetKeyValueComparer()
?? property.GetTypeMapping().KeyComparer;
?? property.FindTypeMapping()?.KeyComparer;

EqualityComparer
= comparer != null
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/ChangeTracking/Internal/StateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@ private static bool KeysEqual(InternalEntityEntry entry, IForeignKey fk, Interna

private static bool KeyValuesEqual(IProperty property, object value, object currentValue)
=> (property.GetKeyValueComparer()
?? property.GetTypeMapping().KeyComparer)
?? property.FindTypeMapping()?.KeyComparer)
?.Equals(currentValue, value)
?? Equals(currentValue, value);

Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/Metadata/Internal/EntityType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2328,7 +2328,7 @@ public virtual IEnumerable<IDictionary<string, object>> GetSeedData(bool provide
{
if (propertyBase is IProperty property)
{
valueConverter = property.GetTypeMapping().Converter
valueConverter = property.FindTypeMapping()?.Converter
?? property.GetValueConverter();
}

Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/Metadata/Internal/EntityTypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ public static PropertyCounts GetCounts([NotNull] this IEntityType entityType)
/// </summary>
public static PropertyCounts CalculateCounts([NotNull] this EntityType entityType)
{
Debug.Assert(entityType.Model.ConventionDispatcher == null, "Should not be called on a mutable model");
Check.DebugAssert(entityType.Model.IsConventionBasedMutableModel, "Should not be called on a mutable model");

var index = 0;
var navigationIndex = 0;
Expand Down
13 changes: 13 additions & 0 deletions src/EFCore/Metadata/Internal/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ private readonly SortedDictionary<string, SortedSet<EntityType>> _entityTypesWit
private readonly Dictionary<string, ConfigurationSource> _ignoredTypeNames
= new Dictionary<string, ConfigurationSource>(StringComparer.Ordinal);

private readonly bool _hasNoConventions;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
Expand All @@ -58,6 +60,7 @@ private readonly Dictionary<string, ConfigurationSource> _ignoredTypeNames
public Model()
: this(new ConventionSet())
{
_hasNoConventions = true;
}

/// <summary>
Expand All @@ -83,6 +86,16 @@ public Model([NotNull] ConventionSet conventions)
/// </summary>
public virtual ConventionDispatcher ConventionDispatcher { [DebuggerStepThrough] get; private set; }

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual bool IsConventionBasedMutableModel
=> _hasNoConventions
|| ConventionDispatcher == null;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/ValueGeneration/ValueGeneratorSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private static ValueGenerator CreateFromFactory(IProperty property, IEntityType

if (factory == null)
{
var mapping = property.GetTypeMapping();
var mapping = property.FindTypeMapping();
factory = mapping?.ValueGeneratorFactory;

if (factory == null)
Expand Down
9 changes: 9 additions & 0 deletions src/Shared/Check.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,14 @@ public static IReadOnlyList<T> HasNoNulls<T>(IReadOnlyList<T> value, [InvokerPar

return value;
}

[Conditional("DEBUG")]
public static void DebugAssert([System.Diagnostics.CodeAnalysis.DoesNotReturnIf(false)] bool condition, string message)
{
if (!condition)
{
throw new Exception($"Check.DebugAssert failed: {message}");
}
}
}
}
16 changes: 16 additions & 0 deletions test/EFCore.SqlServer.FunctionalTests/MigrationsSqlServerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,13 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.HasKey("Id");
b.ToTable("Blogs");
b.HasData(
new
{
Id = 1,
Name = "HalfADonkey"
});
});

modelBuilder.Entity(
Expand Down Expand Up @@ -1349,6 +1356,15 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0");

public DbSet<Blog> Blogs { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().HasData(
new Blog
{
Id = 1, Name = "HalfADonkey"
});
}
}
}

Expand Down

0 comments on commit ef1b09c

Please sign in to comment.