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

Add TPC support to update pipeline #27737

Merged
merged 4 commits into from
Apr 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ public class EntityFrameworkRelationalServicesBuilder : EntityFrameworkServicesB
public static readonly IDictionary<Type, ServiceCharacteristics> RelationalServices
= new Dictionary<Type, ServiceCharacteristics>
{
{ typeof(IKeyValueIndexFactorySource), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IRowKeyValueFactoryFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) },
AndriySvyryd marked this conversation as resolved.
Show resolved Hide resolved
{ typeof(IRowForeignKeyValueFactoryFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IRowIndexValueFactoryFactory), 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 +127,9 @@ public override EntityFrameworkServicesBuilder TryAddCoreServices()
TryAdd<IParameterNameGeneratorFactory, ParameterNameGeneratorFactory>();
TryAdd<IComparer<IReadOnlyModificationCommand>, ModificationCommandComparer>();
TryAdd<IMigrationsIdGenerator, MigrationsIdGenerator>();
TryAdd<IKeyValueIndexFactorySource, KeyValueIndexFactorySource>();
TryAdd<IRowKeyValueFactoryFactory, RowKeyValueFactoryFactory>();
TryAdd<IRowForeignKeyValueFactoryFactory, RowForeignKeyValueFactoryFactory>();
TryAdd<IRowIndexValueFactoryFactory, RowIndexValueFactoryFactory>();
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,40 @@ public sealed record RelationalModelDependencies
/// the constructor at any point in this process.
/// </remarks>
[EntityFrameworkInternal]
public RelationalModelDependencies()
public RelationalModelDependencies(
IRowKeyValueFactoryFactory rowKeyValueFactoryFactory,
IRowForeignKeyValueFactoryFactory foreignKeyRowValueFactorySource,
IRowIndexValueFactoryFactory rowIndexValueFactoryFactory)
{
RowKeyValueFactoryFactory = rowKeyValueFactoryFactory;
RowForeignKeyValueFactoryFactory = foreignKeyRowValueFactorySource;
RowIndexValueFactoryFactory = rowIndexValueFactoryFactory;
}

/// <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; }

/// <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 IRowIndexValueFactoryFactory RowIndexValueFactoryFactory { 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)
AndriySvyryd marked this conversation as resolved.
Show resolved Hide resolved
{
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
24 changes: 21 additions & 3 deletions src/EFCore.Relational/Metadata/IColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface IColumn : IColumnBase
/// <summary>
/// Gets the property mappings.
/// </summary>
new IEnumerable<IColumnMapping> PropertyMappings { get; }
new IReadOnlyList<IColumnMapping> PropertyMappings { get; }

/// <summary>
/// Gets the maximum length of data that is allowed in this column. For example, if the property is a <see cref="string" /> '
Expand Down 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 Expand Up @@ -148,6 +147,25 @@ public virtual string? Collation
=> PropertyMappings.First().Property
.GetCollation(StoreObjectIdentifier.Table(Table.Name, Table.Schema));

/// <summary>
/// Returns the property mapping for the given entity type.
/// </summary>
/// <param name="entityType">An entity type.</param>
/// <returns>The property mapping or <see langword="null" /> if not found.</returns>
public virtual IColumnMapping? FindColumnMapping(IReadOnlyEntityType entityType)
{
for (var i = 0; i < PropertyMappings.Count; i++)
{
var mapping = PropertyMappings[i];
if (mapping.Property.DeclaringEntityType.IsAssignableFrom(entityType))
{
return mapping;
}
}

return null;
}

/// <summary>
/// <para>
/// Creates a human-readable representation of the given metadata.
Expand Down
7 changes: 6 additions & 1 deletion src/EFCore.Relational/Metadata/IColumnBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ public interface IColumnBase : IAnnotatable
/// </summary>
string StoreType { get; }

/// <summary>
/// Gets the provider type.
/// </summary>
Type ProviderClrType { get; }

/// <summary>
/// Gets the value indicating whether the column can contain NULL.
/// </summary>
Expand All @@ -34,5 +39,5 @@ public interface IColumnBase : IAnnotatable
/// <summary>
/// Gets the property mappings.
/// </summary>
IEnumerable<IColumnMappingBase> PropertyMappings { get; }
IReadOnlyList<IColumnMappingBase> PropertyMappings { get; }
}
11 changes: 8 additions & 3 deletions 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 Expand Up @@ -78,11 +83,11 @@ string ToDebugString(MetadataDebugStringOptions options = MetadataDebugStringOpt
.Append(' ')
.Append(Table.Name)
.Append(' ')
.Append(ColumnBase.Format(Columns))
.Append(ColumnBase<IColumnMappingBase>.Format(Columns))
.Append(" -> ")
.Append(PrincipalTable.Name)
.Append(' ')
.Append(ColumnBase.Format(PrincipalColumns));
.Append(ColumnBase<IColumnMappingBase>.Format(PrincipalColumns));

if (OnDeleteAction != ReferentialAction.NoAction)
{
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Metadata/IFunctionColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface IFunctionColumn : IColumnBase
/// <summary>
/// Gets the property mappings.
/// </summary>
new IEnumerable<IFunctionColumnMapping> PropertyMappings { get; }
new IReadOnlyList<IFunctionColumnMapping> PropertyMappings { get; }

/// <summary>
/// <para>
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Metadata/ISqlQueryColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public interface ISqlQueryColumn : IColumnBase
/// <summary>
/// Gets the property mappings.
/// </summary>
new IEnumerable<ISqlQueryColumnMapping> PropertyMappings { get; }
new IReadOnlyList<ISqlQueryColumnMapping> PropertyMappings { get; }

/// <summary>
/// <para>
Expand Down
5 changes: 5 additions & 0 deletions src/EFCore.Relational/Metadata/ITable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public interface ITable : ITableBase
/// </summary>
IEnumerable<IForeignKeyConstraint> ForeignKeyConstraints { get; }

/// <summary>
/// Gets the foreign key constraints referencing this table.
/// </summary>
IEnumerable<IForeignKeyConstraint> ReferencingForeignKeyConstraints { get; }

/// <summary>
/// Gets the unique constraints including the primary key for this table.
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions src/EFCore.Relational/Metadata/ITableBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ public interface ITableBase : IAnnotatable
/// </summary>
string? Schema { get; }

/// <summary>
/// Gets the schema-qualified name of the table in the database.
/// </summary>
string SchemaQualifiedName
=> Schema == null ? Name : Schema + "." + Name;

/// <summary>
/// Gets the database model.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Metadata/IUniqueConstraint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ string ToDebugString(MetadataDebugStringOptions options = MetadataDebugStringOpt
builder
.Append(Name)
.Append(' ')
.Append(ColumnBase.Format(Columns));
.Append(ColumnBase<IColumnMappingBase>.Format(Columns));

if (GetIsPrimaryKey())
{
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Metadata/IViewColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface IViewColumn : IColumnBase
/// <summary>
/// Gets the property mappings.
/// </summary>
new IEnumerable<IViewColumnMapping> PropertyMappings { get; }
new IReadOnlyList<IViewColumnMapping> PropertyMappings { get; }

/// <summary>
/// <para>
Expand Down
23 changes: 20 additions & 3 deletions src/EFCore.Relational/Metadata/Internal/Column.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 @@ -9,8 +12,11 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Internal;
/// 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 class Column : ColumnBase, IColumn
public class Column : ColumnBase<ColumnMapping>, IColumn
{
// Warning: Never access these fields directly as access needs to be thread-safe
private ColumnAccessors? _accessors;

/// <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 @@ -31,6 +37,17 @@ public Column(string name, string type, Table table)
public new virtual Table Table
=> (Table)base.Table;

/// <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 ColumnAccessors Accessors
=> NonCapturingLazyInitializer.EnsureInitialized(
ref _accessors, this, static column =>
ColumnAccessorsFactory.Create(column));

/// <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 @@ -48,9 +65,9 @@ ITable IColumn.Table
}

/// <inheritdoc />
IEnumerable<IColumnMapping> IColumn.PropertyMappings
IReadOnlyList<IColumnMapping> IColumn.PropertyMappings
{
[DebuggerStepThrough]
get => PropertyMappings.Cast<IColumnMapping>();
get => PropertyMappings;
}
}
Loading