Skip to content

Commit

Permalink
Switch the update pipeline to use the relational model
Browse files Browse the repository at this point in the history
Add custom differ logic for seed data

Fixes #22063
  • Loading branch information
AndriySvyryd committed Mar 24, 2022
1 parent bb95ab7 commit 1250db0
Show file tree
Hide file tree
Showing 37 changed files with 1,686 additions and 486 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public class EntityFrameworkRelationalServicesBuilder : EntityFrameworkServicesB
public static readonly IDictionary<Type, ServiceCharacteristics> RelationalServices
= new Dictionary<Type, ServiceCharacteristics>
{
{ typeof(IKeyValueIndexFactorySource), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IRowForeignKeyValueFactoryFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IRowKeyValueFactoryFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IParameterNameGeneratorFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IComparer<IReadOnlyModificationCommand>), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IMigrationsIdGenerator), new ServiceCharacteristics(ServiceLifetime.Singleton) },
Expand Down Expand Up @@ -125,7 +126,8 @@ public override EntityFrameworkServicesBuilder TryAddCoreServices()
TryAdd<IParameterNameGeneratorFactory, ParameterNameGeneratorFactory>();
TryAdd<IComparer<IReadOnlyModificationCommand>, ModificationCommandComparer>();
TryAdd<IMigrationsIdGenerator, MigrationsIdGenerator>();
TryAdd<IKeyValueIndexFactorySource, KeyValueIndexFactorySource>();
TryAdd<IRowForeignKeyValueFactoryFactory, RowForeignKeyValueFactoryFactory>();
TryAdd<IRowKeyValueFactoryFactory, RowKeyValueFactoryFactory>();
TryAdd<IModelCustomizer, RelationalModelCustomizer>();
TryAdd<IModelRuntimeInitializer, RelationalModelRuntimeInitializer>();
TryAdd<IRelationalAnnotationProvider, RelationalAnnotationProvider>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Update.Internal;

namespace Microsoft.EntityFrameworkCore.Infrastructure;

/// <summary>
Expand Down Expand Up @@ -45,7 +47,29 @@ public sealed record RelationalModelDependencies
/// the constructor at any point in this process.
/// </remarks>
[EntityFrameworkInternal]
public RelationalModelDependencies()
public RelationalModelDependencies(
IRowKeyValueFactoryFactory rowKeyValueFactoryFactory,
IRowForeignKeyValueFactoryFactory foreignKeyRowValueFactorySource)
{
RowKeyValueFactoryFactory = rowKeyValueFactoryFactory;
RowForeignKeyValueFactoryFactory = foreignKeyRowValueFactorySource;
}

/// <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>
[EntityFrameworkInternal]
public IRowKeyValueFactoryFactory RowKeyValueFactoryFactory { get; init; }

/// <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>
[EntityFrameworkInternal]
public IRowForeignKeyValueFactoryFactory RowForeignKeyValueFactoryFactory { get; init; }
}
40 changes: 29 additions & 11 deletions src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -559,10 +559,10 @@ protected virtual void ValidateSharedViewCompatibility(
mappedTypes.Add(entityType);
}

foreach (var (table, mappedTypes) in views)
foreach (var (view, mappedTypes) in views)
{
ValidateSharedViewCompatibility(mappedTypes, table.Name, table.Schema, logger);
ValidateSharedColumnsCompatibility(mappedTypes, table, logger);
ValidateSharedViewCompatibility(mappedTypes, view.Name, view.Schema, logger);
ValidateSharedColumnsCompatibility(mappedTypes, view, logger);
}
}

Expand Down Expand Up @@ -866,10 +866,12 @@ protected virtual void ValidateCompatible(
storeObject.DisplayName()));
}

var typeMapping = property.GetRelationalTypeMapping();
var duplicateTypeMapping = duplicateProperty.GetRelationalTypeMapping();
var currentTypeString = property.GetColumnType(storeObject)
?? property.GetRelationalTypeMapping().StoreType;
?? typeMapping.StoreType;
var previousTypeString = duplicateProperty.GetColumnType(storeObject)
?? duplicateProperty.GetRelationalTypeMapping().StoreType;
?? duplicateTypeMapping.StoreType;
if (!string.Equals(currentTypeString, previousTypeString, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
Expand All @@ -884,6 +886,22 @@ protected virtual void ValidateCompatible(
currentTypeString));
}

var currentProviderType = typeMapping.Converter?.ProviderClrType ?? typeMapping.ClrType;
var previousProviderType = duplicateTypeMapping.Converter?.ProviderClrType ?? duplicateTypeMapping.ClrType;
if (currentProviderType != previousProviderType)
{
throw new InvalidOperationException(
RelationalStrings.DuplicateColumnNameProviderTypeMismatch(
duplicateProperty.DeclaringEntityType.DisplayName(),
duplicateProperty.Name,
property.DeclaringEntityType.DisplayName(),
property.Name,
columnName,
storeObject.DisplayName(),
previousProviderType.ShortDisplayName(),
currentProviderType.ShortDisplayName()));
}

var currentComputedColumnSql = property.GetComputedColumnSql(storeObject) ?? "";
var previousComputedColumnSql = duplicateProperty.GetComputedColumnSql(storeObject) ?? "";
if (!currentComputedColumnSql.Equals(previousComputedColumnSql, StringComparison.OrdinalIgnoreCase))
Expand Down Expand Up @@ -1340,8 +1358,8 @@ protected override void ValidateInheritanceMapping(
RelationalStrings.NonTphMappingStrategy(mappingStrategy, entityType.DisplayName()));
}

ValidateTPHMapping(entityType, forTables: false);
ValidateTPHMapping(entityType, forTables: true);
ValidateTphMapping(entityType, forTables: false);
ValidateTphMapping(entityType, forTables: true);
ValidateDiscriminatorValues(entityType);
}
else
Expand All @@ -1362,8 +1380,8 @@ protected override void ValidateInheritanceMapping(
RelationalStrings.KeylessMappingStrategy(mappingStrategy ?? RelationalAnnotationNames.TptMappingStrategy, entityType.DisplayName()));
}

ValidateNonTPHMapping(entityType, forTables: false);
ValidateNonTPHMapping(entityType, forTables: true);
ValidateNonTphMapping(entityType, forTables: false);
ValidateNonTphMapping(entityType, forTables: true);
}
}
}
Expand All @@ -1387,7 +1405,7 @@ protected virtual void ValidateMappingStrategy(string? mappingStrategy, IEntityT
};
}

private static void ValidateNonTPHMapping(IEntityType rootEntityType, bool forTables)
private static void ValidateNonTphMapping(IEntityType rootEntityType, bool forTables)
{
var derivedTypes = new Dictionary<(string, string?), IEntityType>();
foreach (var entityType in rootEntityType.GetDerivedTypesInclusive())
Expand All @@ -1413,7 +1431,7 @@ private static void ValidateNonTPHMapping(IEntityType rootEntityType, bool forTa
}
}

private static void ValidateTPHMapping(IEntityType rootEntityType, bool forTables)
private static void ValidateTphMapping(IEntityType rootEntityType, bool forTables)
{
string? firstName = null;
string? firstSchema = null;
Expand Down
3 changes: 1 addition & 2 deletions src/EFCore.Relational/Metadata/IColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ public virtual bool TryGetDefaultValue(out object? defaultValue)
continue;
}

var converter = property.GetValueConverter() ?? PropertyMappings.First().TypeMapping.Converter;

var converter = property.GetValueConverter() ?? mapping.TypeMapping.Converter;
if (converter != null)
{
defaultValue = converter.ConvertToProvider(defaultValue);
Expand Down
12 changes: 12 additions & 0 deletions src/EFCore.Relational/Metadata/IColumnBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ public interface IColumnBase : IAnnotatable
/// </summary>
string StoreType { get; }

/// <summary>
/// Gets the provider type.
/// </summary>
Type ProviderClrType
{
get
{
var typeMapping = PropertyMappings.First().TypeMapping;
return typeMapping.Converter?.ProviderClrType ?? typeMapping.ClrType;
}
}

/// <summary>
/// Gets the value indicating whether the column can contain NULL.
/// </summary>
Expand Down
7 changes: 6 additions & 1 deletion src/EFCore.Relational/Metadata/IForeignKeyConstraint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ public interface IForeignKeyConstraint : IAnnotatable
/// <summary>
/// Gets the columns that are referenced by the foreign key constraint.
/// </summary>
IReadOnlyList<IColumn> PrincipalColumns { get; }
IReadOnlyList<IColumn> PrincipalColumns => PrincipalUniqueConstraint.Columns;

/// <summary>
/// Gets the unique constraint on the columns referenced by the foreign key constraint.
/// </summary>
IUniqueConstraint PrincipalUniqueConstraint { get; }

/// <summary>
/// Gets the action to be performed when the referenced row is deleted.
Expand Down
34 changes: 31 additions & 3 deletions src/EFCore.Relational/Metadata/Internal/ForeignKeyConstraint.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Update.Internal;

namespace Microsoft.EntityFrameworkCore.Metadata.Internal;

/// <summary>
Expand All @@ -22,14 +25,14 @@ public ForeignKeyConstraint(
Table table,
Table principalTable,
IReadOnlyList<Column> columns,
IReadOnlyList<Column> principalColumns,
UniqueConstraint principalUniqueConstraint,
ReferentialAction onDeleteAction)
{
Name = name;
Table = table;
PrincipalTable = principalTable;
Columns = columns;
PrincipalColumns = principalColumns;
PrincipalUniqueConstraint = principalUniqueConstraint;
OnDeleteAction = onDeleteAction;
}

Expand Down Expand Up @@ -74,7 +77,15 @@ public ForeignKeyConstraint(
/// 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 IReadOnlyList<Column> PrincipalColumns { get; }
public virtual IReadOnlyList<Column> PrincipalColumns => PrincipalUniqueConstraint.Columns;

/// <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 UniqueConstraint PrincipalUniqueConstraint { get; }

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand All @@ -88,6 +99,19 @@ public override bool IsReadOnly
/// <inheritdoc />
public virtual ReferentialAction OnDeleteAction { get; set; }

private IRowForeignKeyValueFactory? _foreignKeyRowValueFactory;

/// <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 IRowForeignKeyValueFactory GetRowForeignKeyValueFactory()
=> NonCapturingLazyInitializer.EnsureInitialized(
ref _foreignKeyRowValueFactory, this,
static constraint => constraint.Table.Model.Model.GetRelationalDependencies().RowForeignKeyValueFactoryFactory.Create(constraint));

/// <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 Expand Up @@ -116,4 +140,8 @@ IReadOnlyList<IColumn> IForeignKeyConstraint.Columns
/// <inheritdoc />
IReadOnlyList<IColumn> IForeignKeyConstraint.PrincipalColumns
=> PrincipalColumns;

/// <inheritdoc />
IUniqueConstraint IForeignKeyConstraint.PrincipalUniqueConstraint
=> PrincipalUniqueConstraint;
}
Loading

0 comments on commit 1250db0

Please sign in to comment.