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 for data seeding #27903

Merged
merged 3 commits into from
Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class EntityFrameworkRelationalServicesBuilder : EntityFrameworkServicesB
{ typeof(IRowKeyValueFactoryFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IRowForeignKeyValueFactoryFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IRowIndexValueFactoryFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IRowIdentityMapFactory), 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 @@ -130,6 +131,7 @@ public override EntityFrameworkServicesBuilder TryAddCoreServices()
TryAdd<IRowKeyValueFactoryFactory, RowKeyValueFactoryFactory>();
TryAdd<IRowForeignKeyValueFactoryFactory, RowForeignKeyValueFactoryFactory>();
TryAdd<IRowIndexValueFactoryFactory, RowIndexValueFactoryFactory>();
TryAdd<IRowIdentityMapFactory, RowIdentityMapFactory>();
TryAdd<IModelCustomizer, RelationalModelCustomizer>();
TryAdd<IModelRuntimeInitializer, RelationalModelRuntimeInitializer>();
TryAdd<IRelationalAnnotationProvider, RelationalAnnotationProvider>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore.Metadata.Internal;

/// <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 sealed class TableBaseIdentityComparer : IEqualityComparer<ITableBase>
{
private TableBaseIdentityComparer()
{
}

/// <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 static readonly TableBaseIdentityComparer Instance = new();

/// <inheritdoc />
public bool Equals(ITableBase? x, ITableBase? y)
=> ReferenceEquals(x, y)
|| (x is null
? y is null
: y is not null && x.Name == y.Name && x.Schema == y.Schema);

/// <inheritdoc />
public int GetHashCode(ITableBase obj)
=> HashCode.Combine(obj.Name, obj.Schema);
}
788 changes: 345 additions & 443 deletions src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs

Large diffs are not rendered by default.

20 changes: 13 additions & 7 deletions src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -888,8 +888,10 @@ protected virtual IUpdateSqlGenerator SqlGenerator

for (var i = 0; i < operation.Values.GetLength(0); i++)
{
var modificationCommand = Dependencies.ModificationCommandFactory.CreateModificationCommand(
new ModificationCommandParameters(operation.Table, operation.Schema ?? model?.GetDefaultSchema(), SensitiveLoggingEnabled));
var modificationCommand = Dependencies.ModificationCommandFactory.CreateNonTrackedModificationCommand(
new NonTrackedModificationCommandParameters(operation.Table, operation.Schema ?? model?.GetDefaultSchema(), SensitiveLoggingEnabled));
modificationCommand.EntityState = EntityState.Added;

for (var j = 0; j < operation.Columns.Length; j++)
{
var name = operation.Columns[j];
Expand Down Expand Up @@ -977,8 +979,10 @@ protected virtual IUpdateSqlGenerator SqlGenerator

for (var i = 0; i < operation.KeyValues.GetLength(0); i++)
{
var modificationCommand = Dependencies.ModificationCommandFactory.CreateModificationCommand(
new ModificationCommandParameters(operation.Table, operation.Schema, SensitiveLoggingEnabled));
var modificationCommand = Dependencies.ModificationCommandFactory.CreateNonTrackedModificationCommand(
new NonTrackedModificationCommandParameters(operation.Table, operation.Schema, SensitiveLoggingEnabled));
modificationCommand.EntityState = EntityState.Deleted;

for (var j = 0; j < operation.KeyColumns.Length; j++)
{
var name = operation.KeyColumns[j];
Expand Down Expand Up @@ -1091,8 +1095,10 @@ protected virtual IUpdateSqlGenerator SqlGenerator

for (var i = 0; i < operation.KeyValues.GetLength(0); i++)
{
var modificationCommand = Dependencies.ModificationCommandFactory.CreateModificationCommand(
new ModificationCommandParameters(operation.Table, operation.Schema, SensitiveLoggingEnabled));
var modificationCommand = Dependencies.ModificationCommandFactory.CreateNonTrackedModificationCommand(
new NonTrackedModificationCommandParameters(operation.Table, operation.Schema, SensitiveLoggingEnabled));
modificationCommand.EntityState = EntityState.Modified;

for (var j = 0; j < operation.KeyColumns.Length; j++)
{
var name = operation.KeyColumns[j];
Expand Down Expand Up @@ -1127,7 +1133,7 @@ protected virtual IUpdateSqlGenerator SqlGenerator
modificationCommand.AddColumnModification(
new ColumnModificationParameters(
name, originalValue: null, value, propertyMapping?.Property, columnType, typeMapping,
read: false, write: true, key: true, condition: false,
read: false, write: true, key: false, condition: false,
SensitiveLoggingEnabled, propertyMapping?.Column.IsNullable));
}

Expand Down
12 changes: 6 additions & 6 deletions src/EFCore.Relational/Storage/RelationalDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ namespace Microsoft.EntityFrameworkCore.Storage;
/// </remarks>
public class RelationalDatabase : Database
{
private IUpdateAdapter? _updateAdapter;

/// <summary>
/// Initializes a new instance of the <see cref="RelationalDatabase" /> class.
/// </summary>
Expand All @@ -39,6 +41,8 @@ public class RelationalDatabase : Database
RelationalDependencies = relationalDependencies;
}

private IUpdateAdapter UpdateAdapter => _updateAdapter ??= Dependencies.UpdateAdapterFactory.Create();

/// <summary>
/// Relational provider-specific dependencies for this service.
/// </summary>
Expand All @@ -51,9 +55,7 @@ public class RelationalDatabase : Database
/// <returns>The number of state entries persisted to the database.</returns>
public override int SaveChanges(IList<IUpdateEntry> entries)
=> RelationalDependencies.BatchExecutor.Execute(
RelationalDependencies.BatchPreparer.BatchCommands(
entries,
Dependencies.UpdateAdapterFactory.Create()),
RelationalDependencies.BatchPreparer.BatchCommands(entries, UpdateAdapter),
RelationalDependencies.Connection);

/// <summary>
Expand All @@ -70,9 +72,7 @@ public override int SaveChanges(IList<IUpdateEntry> entries)
IList<IUpdateEntry> entries,
CancellationToken cancellationToken = default)
=> RelationalDependencies.BatchExecutor.ExecuteAsync(
RelationalDependencies.BatchPreparer.BatchCommands(
entries,
Dependencies.UpdateAdapterFactory.Create()),
RelationalDependencies.BatchPreparer.BatchCommands(entries, UpdateAdapter),
RelationalDependencies.Connection,
cancellationToken);
}
44 changes: 34 additions & 10 deletions src/EFCore.Relational/Update/ColumnModification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class ColumnModification : IColumnModification
private string? _parameterName;
private string? _originalParameterName;
private readonly Func<string>? _generateParameterName;
private readonly object? _originalValue;
private object? _originalValue;
private object? _value;
private readonly bool _sensitiveLoggingEnabled;
private List<IColumnModification>? _sharedColumnModifications;
Expand All @@ -37,6 +37,7 @@ public class ColumnModification : IColumnModification
/// <param name="columnModificationParameters">Creation parameters.</param>
public ColumnModification(in ColumnModificationParameters columnModificationParameters)
{
Column = columnModificationParameters.Column;
ColumnName = columnModificationParameters.ColumnName;
_originalValue = columnModificationParameters.OriginalValue;
_value = columnModificationParameters.Value;
Expand All @@ -61,23 +62,26 @@ public ColumnModification(in ColumnModificationParameters columnModificationPara
/// <inheritdoc />
public virtual IProperty? Property { get; }

/// <inheritdoc />
public virtual IColumn? Column { get; }

/// <inheritdoc />
public virtual RelationalTypeMapping? TypeMapping { get; }

/// <inheritdoc />
public virtual bool? IsNullable { get; }

/// <inheritdoc />
public virtual bool IsRead { get; }
public virtual bool IsRead { get; set; }
AndriySvyryd marked this conversation as resolved.
Show resolved Hide resolved

/// <inheritdoc />
public virtual bool IsWrite { get; }
public virtual bool IsWrite { get; set; }

/// <inheritdoc />
public virtual bool IsCondition { get; }
public virtual bool IsCondition { get; set; }

/// <inheritdoc />
public virtual bool IsKey { get; }
public virtual bool IsKey { get; set; }

/// <inheritdoc />
public virtual bool UseOriginalValueParameter
Expand Down Expand Up @@ -114,11 +118,31 @@ public virtual bool UseCurrentValue

/// <inheritdoc />
public virtual object? OriginalValue
=> Entry == null
? _originalValue
: Entry.SharedIdentityEntry == null
? Entry.GetOriginalValue(Property!)
: Entry.SharedIdentityEntry.GetOriginalValue(Property!);
{
get => Entry == null
? _originalValue
roji marked this conversation as resolved.
Show resolved Hide resolved
: Entry.SharedIdentityEntry == null
? Entry.GetOriginalValue(Property!)
: Entry.SharedIdentityEntry.GetOriginalValue(Property!);
set
{
if (Entry == null)
{
_originalValue = value;
}
else
{
Entry.SetOriginalValue(Property!, value);
if (_sharedColumnModifications != null)
{
foreach (var sharedModification in _sharedColumnModifications)
{
sharedModification.OriginalValue = value;
}
}
}
}
}

/// <inheritdoc />
public virtual object? Value
Expand Down
52 changes: 52 additions & 0 deletions src/EFCore.Relational/Update/ColumnModificationParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ namespace Microsoft.EntityFrameworkCore.Update;
/// Indicates whether the column is part of a primary or alternate key.
/// </summary>
public bool IsKey { get; init; }

/// <summary>
/// The column.
/// </summary>
public IColumn? Column { get; init; }

/// <summary>
/// The name of the column.
Expand Down Expand Up @@ -116,6 +121,7 @@ namespace Microsoft.EntityFrameworkCore.Update;
bool sensitiveLoggingEnabled,
bool? isNullable = null)
{
Column = null;
ColumnName = columnName;
OriginalValue = originalValue;
Value = value;
Expand All @@ -132,6 +138,51 @@ namespace Microsoft.EntityFrameworkCore.Update;
GenerateParameterName = null;
Entry = null;
}

/// <summary>
/// Creates a new <see cref="ColumnModificationParameters" /> instance.
/// </summary>
/// <param name="column">The column.</param>
/// <param name="originalValue">The original value of the property mapped to this column.</param>
/// <param name="value">The current value of the property mapped to this column.</param>
/// <param name="property">The property that maps to the column.</param>
/// <param name="typeMapping">The relational type mapping to be used for the command parameter.</param>
/// <param name="read">Indicates whether a value must be read from the database for the column.</param>
/// <param name="write">Indicates whether a value must be written to the database for the column.</param>
/// <param name="key">Indicates whether the column part of a primary or alternate key.</param>
/// <param name="condition">Indicates whether the column is used in the <c>WHERE</c> clause when updating.</param>
/// <param name="sensitiveLoggingEnabled">Indicates whether potentially sensitive data (e.g. database values) can be logged.</param>
/// <param name="isNullable">A value indicating whether the value could be null.</param>
public ColumnModificationParameters(
IColumn column,
object? originalValue,
object? value,
IProperty? property,
RelationalTypeMapping? typeMapping,
bool read,
bool write,
bool key,
bool condition,
bool sensitiveLoggingEnabled,
bool? isNullable = null)
{
Column = column;
ColumnName = column.Name;
OriginalValue = originalValue;
Value = value;
Property = property;
ColumnType = column.StoreType;
TypeMapping = typeMapping;
IsRead = read;
IsWrite = write;
IsKey = key;
IsCondition = condition;
SensitiveLoggingEnabled = sensitiveLoggingEnabled;
IsNullable = isNullable;

GenerateParameterName = null;
Entry = null;
}

/// <summary>
/// Creates a new <see cref="ColumnModificationParameters" /> instance.
Expand All @@ -158,6 +209,7 @@ namespace Microsoft.EntityFrameworkCore.Update;
bool columnIsCondition,
bool sensitiveLoggingEnabled)
{
Column = column;
ColumnName = column.Name;
OriginalValue = null;
Value = null;
Expand Down
15 changes: 10 additions & 5 deletions src/EFCore.Relational/Update/IColumnModification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public interface IColumnModification
/// </summary>
public IProperty? Property { get; }

/// <summary>
/// The column.
/// </summary>
public IColumn? Column { get; }

/// <summary>
/// The relational type mapping for the column.
/// </summary>
Expand All @@ -43,22 +48,22 @@ public interface IColumnModification
/// <summary>
/// Indicates whether a value must be read from the database for the column.
/// </summary>
public bool IsRead { get; }
public bool IsRead { get; set; }

/// <summary>
/// Indicates whether a value must be written to the database for the column.
/// </summary>
public bool IsWrite { get; }
public bool IsWrite { get; set; }

/// <summary>
/// Indicates whether the column is used in the <c>WHERE</c> clause when updating.
/// </summary>
public bool IsCondition { get; }
public bool IsCondition { get; set; }

/// <summary>
/// Indicates whether the column is part of a primary or alternate key.
/// </summary>
public bool IsKey { get; }
public bool IsKey { get; set; }

/// <summary>
/// Indicates whether the original value of the property must be passed as a parameter to the SQL.
Expand Down Expand Up @@ -110,7 +115,7 @@ public interface IColumnModification
/// <summary>
/// The original value of the property mapped to this column.
/// </summary>
public object? OriginalValue { get; }
public object? OriginalValue { get; set; }

/// <summary>
/// Gets or sets the current value of the property mapped to this column.
Expand Down
7 changes: 0 additions & 7 deletions src/EFCore.Relational/Update/IModificationCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,4 @@ public interface IModificationCommand : IReadOnlyModificationCommand
/// <param name="entry">Entry object.</param>
/// <param name="mainEntry">Whether this is the main entry. Only one main entry can be added to a given command.</param>
public void AddEntry(IUpdateEntry entry, bool mainEntry);

/// <summary>
/// Creates a new <see cref="IColumnModification" /> and add it to this command.
/// </summary>
/// <param name="columnModificationParameters">Creation parameters.</param>
/// <returns>The new <see cref="IColumnModification" /> instance.</returns>
IColumnModification AddColumnModification(in ColumnModificationParameters columnModificationParameters);
}
8 changes: 8 additions & 0 deletions src/EFCore.Relational/Update/IModificationCommandFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,12 @@ public interface IModificationCommandFactory
/// <returns>A new <see cref="IModificationCommand" /> instance.</returns>
IModificationCommand CreateModificationCommand(
in ModificationCommandParameters modificationCommandParameters);

/// <summary>
/// Creates a new database CUD command.
/// </summary>
/// <param name="modificationCommandParameters">The creation parameters.</param>
/// <returns>A new <see cref="INonTrackedModificationCommand" /> instance.</returns>
INonTrackedModificationCommand CreateNonTrackedModificationCommand(
in NonTrackedModificationCommandParameters modificationCommandParameters);
}