From b69c2f3e1a320bb51bdfe98e5bab8f73ef75a693 Mon Sep 17 00:00:00 2001 From: Umit Kavala Date: Mon, 31 May 2021 02:32:33 +0200 Subject: [PATCH] Warn when saving an optional dependent with all null properties when table splitting Fixes #24558 Co-authored-by: Umit Kavala --- .../Diagnostics/RelationalEventId.cs | 17 +- .../Diagnostics/RelationalLoggerExtensions.cs | 69 +++++++++ .../RelationalLoggingDefinitions.cs | 18 +++ .../Properties/RelationalStrings.Designer.cs | 50 ++++++ .../Properties/RelationalStrings.resx | 8 + .../Update/Internal/CommandBatchPreparer.cs | 4 +- .../Update/ModificationCommand.cs | 32 +++- src/EFCore/Diagnostics/EntityTypeEventData.cs | 1 + .../Diagnostics/UpdateEntryEventData.cs | 36 +++++ .../TableSplittingTestBase.cs | 145 +++++++++++++++++- .../RelationalEventIdTest.cs | 4 +- .../TestUtilities/FakeModificationCommand.cs | 2 +- .../Update/ModificationCommandComparerTest.cs | 44 +++--- .../Update/ModificationCommandTest.cs | 30 ++-- .../ReaderModificationCommandBatchTest.cs | 28 ++-- ...rverModificationCommandBatchFactoryTest.cs | 8 +- .../SqlServerModificationCommandBatchTest.cs | 4 +- 17 files changed, 436 insertions(+), 64 deletions(-) create mode 100644 src/EFCore/Diagnostics/UpdateEntryEventData.cs diff --git a/src/EFCore.Relational/Diagnostics/RelationalEventId.cs b/src/EFCore.Relational/Diagnostics/RelationalEventId.cs index 2e50352b9e9..fecf4f2c5c0 100644 --- a/src/EFCore.Relational/Diagnostics/RelationalEventId.cs +++ b/src/EFCore.Relational/Diagnostics/RelationalEventId.cs @@ -94,6 +94,7 @@ private enum Id BatchSmallerThanMinBatchSize, BatchExecutorFailedToRollbackToSavepoint, BatchExecutorFailedToReleaseSavepoint, + OptionalDependentWithAllNullPropertiesWarning, } private static readonly string _connectionPrefix = DbLoggerCategory.Database.Connection.Name + "."; @@ -726,7 +727,7 @@ private static EventId MakeValidationId(Id id) /// /// - /// A foreign key specifies properties which don't map to the related tables. + /// The entity does not have any property with a non-default value to identify whether the entity exists. /// /// /// This event is in the category. @@ -790,5 +791,19 @@ private static EventId MakeUpdateId(Id id) /// /// public static readonly EventId BatchExecutorFailedToReleaseSavepoint = MakeUpdateId(Id.BatchExecutorFailedToReleaseSavepoint); + + /// + /// + /// The entity does not have any property with a non-default value to identify whether the entity exists. + /// + /// + /// This event is in the category. + /// + /// + /// This event uses the payload when used with a . + /// + /// + public static readonly EventId OptionalDependentWithAllNullPropertiesWarning + = MakeUpdateId(Id.OptionalDependentWithAllNullPropertiesWarning); } } diff --git a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs index 55146ed3e93..54da7f59b28 100644 --- a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs +++ b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs @@ -2964,5 +2964,74 @@ public static void BatchExecutorFailedToReleaseSavepoint( diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); } } + + /// + /// Logs the event. + /// + /// The diagnostics logger to use. + /// The entry. + public static void OptionalDependentWithAllNullPropertiesWarning( + this IDiagnosticsLogger diagnostics, + IUpdateEntry entry) + { + var definition = RelationalResources.LogOptionalDependentWithAllNullProperties(diagnostics); + + if (diagnostics.ShouldLog(definition)) + { + definition.Log(diagnostics, entry.EntityType.DisplayName()); + } + + if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled)) + { + var eventData = new UpdateEntryEventData( + definition, + OptionalDependentWithAllNullPropertiesWarning, + entry); + + diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); + } + } + + private static string OptionalDependentWithAllNullPropertiesWarning(EventDefinitionBase definition, EventData payload) + { + var d = (EventDefinition)definition; + var p = (UpdateEntryEventData)payload; + return d.GenerateMessage(p.EntityEntry.EntityType.DisplayName()); + } + + /// + /// Logs the event. + /// + /// The diagnostics logger to use. + /// The entry. + public static void OptionalDependentWithAllNullPropertiesWarningSensitive( + this IDiagnosticsLogger diagnostics, + IUpdateEntry entry) + { + var definition = RelationalResources.LogOptionalDependentWithAllNullPropertiesSensitive(diagnostics); + + if (diagnostics.ShouldLog(definition)) + { + definition.Log(diagnostics, entry.EntityType.DisplayName(), entry.BuildCurrentValuesString(entry.EntityType.FindPrimaryKey()!.Properties)); + } + + if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled)) + { + var eventData = new UpdateEntryEventData( + definition, + OptionalDependentWithAllNullPropertiesWarningSensitive, + entry + ); + + diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); + } + } + + private static string OptionalDependentWithAllNullPropertiesWarningSensitive(EventDefinitionBase definition, EventData payload) + { + var d = (EventDefinition)definition; + var p = (UpdateEntryEventData)payload; + return d.GenerateMessage(p.EntityEntry.EntityType.DisplayName(), p.EntityEntry.BuildCurrentValuesString(p.EntityEntry.EntityType.FindPrimaryKey()!.Properties)); + } } } diff --git a/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs b/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs index 827e92706b1..49e51fb6a62 100644 --- a/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs +++ b/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs @@ -512,5 +512,23 @@ public abstract class RelationalLoggingDefinitions : LoggingDefinitions /// [EntityFrameworkInternal] public EventDefinitionBase? LogOptionalDependentWithoutIdentifyingProperty; + + /// + /// 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. + /// + [EntityFrameworkInternal] + public EventDefinitionBase? LogOptionalDependentWithAllNullProperties; + + /// + /// 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. + /// + [EntityFrameworkInternal] + public EventDefinitionBase? LogOptionalDependentWithAllNullPropertiesSensitive; } } diff --git a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs index a93c36795be..9b9499926e6 100644 --- a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs +++ b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs @@ -2237,6 +2237,56 @@ public static EventDefinition LogOpeningConnection(IDiagnosticsL return (EventDefinition)definition; } + /// + /// The entity of type '{entityType}' is an optional dependent using table sharing. The entity does not have any property with a non-default value to identify whether the entity exists. This means that when it is queried no object instance will be created instead of an instance with all properties set to default values. Any nested dependents will also be lost. Either don't save any instance with only default values or mark the incoming navigation as required in the model. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the key values of the entity. + /// + public static EventDefinition LogOptionalDependentWithAllNullProperties(IDiagnosticsLogger logger) + { + var definition = ((RelationalLoggingDefinitions)logger.Definitions).LogOptionalDependentWithAllNullProperties; + if (definition == null) + { + definition = NonCapturingLazyInitializer.EnsureInitialized( + ref ((RelationalLoggingDefinitions)logger.Definitions).LogOptionalDependentWithAllNullProperties, + logger, + static logger => new EventDefinition( + logger.Options, + RelationalEventId.OptionalDependentWithAllNullPropertiesWarning, + LogLevel.Warning, + "RelationalEventId.OptionalDependentWithAllNullPropertiesWarning", + level => LoggerMessage.Define( + level, + RelationalEventId.OptionalDependentWithAllNullPropertiesWarning, + _resourceManager.GetString("LogOptionalDependentWithAllNullProperties")!))); + } + + return (EventDefinition)definition; + } + + /// + /// The entity of type '{entityType}' with primary key values {keyValues} is an optional dependent using table sharing. The entity does not have any property with a non-default value to identify whether the entity exists. This means that when it is queried no object instance will be created instead of an instance with all properties set to default values. Any nested dependents will also be lost. Either don't save any instance with only default values or mark the incoming navigation as required in the model. + /// + public static EventDefinition LogOptionalDependentWithAllNullPropertiesSensitive(IDiagnosticsLogger logger) + { + var definition = ((RelationalLoggingDefinitions)logger.Definitions).LogOptionalDependentWithAllNullPropertiesSensitive; + if (definition == null) + { + definition = NonCapturingLazyInitializer.EnsureInitialized( + ref ((RelationalLoggingDefinitions)logger.Definitions).LogOptionalDependentWithAllNullPropertiesSensitive, + logger, + static logger => new EventDefinition( + logger.Options, + RelationalEventId.OptionalDependentWithAllNullPropertiesWarning, + LogLevel.Warning, + "RelationalEventId.OptionalDependentWithAllNullPropertiesWarning", + level => LoggerMessage.Define( + level, + RelationalEventId.OptionalDependentWithAllNullPropertiesWarning, + _resourceManager.GetString("LogOptionalDependentWithAllNullPropertiesSensitive")!))); + } + + return (EventDefinition)definition; + } + /// /// The entity type '{entityType}' is an optional dependent using table sharing without any required non shared property that could be used to identify whether the entity exists. If all nullable properties contain a null value in database then an object instance won't be created in the query. Add a required property to create instances with null values for other properties or mark the incoming navigation as required to always create an instance. /// diff --git a/src/EFCore.Relational/Properties/RelationalStrings.resx b/src/EFCore.Relational/Properties/RelationalStrings.resx index 30275791f6d..04aed56da26 100644 --- a/src/EFCore.Relational/Properties/RelationalStrings.resx +++ b/src/EFCore.Relational/Properties/RelationalStrings.resx @@ -559,6 +559,14 @@ Opening connection to database '{database}' on server '{server}'. Debug RelationalEventId.ConnectionOpening string string + + The entity of type '{entityType}' is an optional dependent using table sharing. The entity does not have any property with a non-default value to identify whether the entity exists. This means that when it is queried no object instance will be created instead of an instance with all properties set to default values. Any nested dependents will also be lost. Either don't save any instance with only default values or mark the incoming navigation as required in the model. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the key values of the entity. + Warning RelationalEventId.OptionalDependentWithAllNullPropertiesWarning string + + + The entity of type '{entityType}' with primary key values {keyValues} is an optional dependent using table sharing. The entity does not have any property with a non-default value to identify whether the entity exists. This means that when it is queried no object instance will be created instead of an instance with all properties set to default values. Any nested dependents will also be lost. Either don't save any instance with only default values or mark the incoming navigation as required in the model. + Warning RelationalEventId.OptionalDependentWithAllNullPropertiesWarning string string + The entity type '{entityType}' is an optional dependent using table sharing without any required non shared property that could be used to identify whether the entity exists. If all nullable properties contain a null value in database then an object instance won't be created in the query. Add a required property to create instances with null values for other properties or mark the incoming navigation as required to always create an instance. Warning RelationalEventId.OptionalDependentWithoutIdentifyingPropertyWarning string diff --git a/src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs b/src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs index 5b525859caf..62a3cd921d7 100644 --- a/src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs +++ b/src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs @@ -199,13 +199,13 @@ protected virtual IEnumerable CreateModificationCommands( command = sharedCommandsMap.GetOrAddValue( entry, - (n, s, c) => new ModificationCommand(n, s, generateParameterName, _sensitiveLoggingEnabled, c)); + (n, s, c) => new ModificationCommand(n, s, generateParameterName, _sensitiveLoggingEnabled, c, Dependencies.UpdateLogger)); isMainEntry = sharedCommandsMap.IsMainEntry(entry); } else { command = new ModificationCommand( - table.Name, table.Schema, generateParameterName, _sensitiveLoggingEnabled, comparer: null); + table.Name, table.Schema, generateParameterName, _sensitiveLoggingEnabled, comparer: null, Dependencies.UpdateLogger); } command.AddEntry(entry, isMainEntry); diff --git a/src/EFCore.Relational/Update/ModificationCommand.cs b/src/EFCore.Relational/Update/ModificationCommand.cs index 65a8cb0d846..8ddf4d40fd7 100644 --- a/src/EFCore.Relational/Update/ModificationCommand.cs +++ b/src/EFCore.Relational/Update/ModificationCommand.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Linq; using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Diagnostics.Internal; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata; @@ -31,6 +32,7 @@ public class ModificationCommand private IReadOnlyList? _columnModifications; private bool _requiresResultPropagation; private bool _mainEntryAdded; + private readonly IDiagnosticsLogger? _logger; /// /// Initializes a new instance. @@ -40,12 +42,14 @@ public class ModificationCommand /// A delegate to generate parameter names. /// Indicates whether or not potentially sensitive data (e.g. database values) can be logged. /// A for s. + /// A for s. public ModificationCommand( string name, string? schema, Func generateParameterName, bool sensitiveLoggingEnabled, - IComparer? comparer) + IComparer? comparer, + IDiagnosticsLogger? logger) : this( Check.NotEmpty(name, nameof(name)), schema, @@ -56,6 +60,7 @@ public ModificationCommand( _generateParameterName = generateParameterName; _comparer = comparer; + _logger = logger; } /// @@ -306,6 +311,12 @@ private IReadOnlyList GenerateColumnModifications() continue; } + var optionalDependentWithAllNull = + (entry.EntityState == EntityState.Deleted + || entry.EntityState == EntityState.Added) + && tableMapping.Table.IsOptional(entry.EntityType) + && tableMapping.Table.GetRowInternalForeignKeys(entry.EntityType).Any(); + foreach (var columnMapping in tableMapping.ColumnMappings) { var property = columnMapping.Property; @@ -367,6 +378,25 @@ private IReadOnlyList GenerateColumnModifications() } columnModifications.Add(columnModification); + + if (optionalDependentWithAllNull + && columnModification.IsWrite + && (entry.EntityState != EntityState.Added || columnModification.Value is not null)) + { + optionalDependentWithAllNull = false; + } + } + } + + if (optionalDependentWithAllNull && _logger != null) + { + if (_sensitiveLoggingEnabled) + { + _logger.OptionalDependentWithAllNullPropertiesWarningSensitive(entry); + } + else + { + _logger.OptionalDependentWithAllNullPropertiesWarning(entry); } } } diff --git a/src/EFCore/Diagnostics/EntityTypeEventData.cs b/src/EFCore/Diagnostics/EntityTypeEventData.cs index ed45c391e60..0cd378f71d9 100644 --- a/src/EFCore/Diagnostics/EntityTypeEventData.cs +++ b/src/EFCore/Diagnostics/EntityTypeEventData.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Update; namespace Microsoft.EntityFrameworkCore.Diagnostics { diff --git a/src/EFCore/Diagnostics/UpdateEntryEventData.cs b/src/EFCore/Diagnostics/UpdateEntryEventData.cs new file mode 100644 index 00000000000..68b92d0ec3b --- /dev/null +++ b/src/EFCore/Diagnostics/UpdateEntryEventData.cs @@ -0,0 +1,36 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Diagnostics; +using Microsoft.EntityFrameworkCore.Update; + +namespace Microsoft.EntityFrameworkCore.Diagnostics +{ + /// + /// A event payload class for events that have + /// an entity update entry. + /// + public class UpdateEntryEventData : EventData + { + /// + /// Constructs the event payload. + /// + /// The event definition. + /// A delegate that generates a log message for this event. + /// The entry for the entity instance on which the property value has changed. + public UpdateEntryEventData( + EventDefinitionBase eventDefinition, + Func messageGenerator, + IUpdateEntry entityEntry) + : base(eventDefinition, messageGenerator) + { + EntityEntry = entityEntry; + } + + /// + /// The entry for the entity instance on which the property value has changed. + /// + public virtual IUpdateEntry EntityEntry { get; } + } +} diff --git a/test/EFCore.Relational.Specification.Tests/TableSplittingTestBase.cs b/test/EFCore.Relational.Specification.Tests/TableSplittingTestBase.cs index 8d00a4643c7..51834115637 100644 --- a/test/EFCore.Relational.Specification.Tests/TableSplittingTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/TableSplittingTestBase.cs @@ -4,6 +4,8 @@ using System; using System.Linq; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Diagnostics.Internal; using Microsoft.EntityFrameworkCore.TestModels.TransportationModel; using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; @@ -362,7 +364,7 @@ await InitializeAsync( } } - [ConditionalFact] + [ConditionalFact(Skip = "Issue #24970")] public virtual async Task Can_insert_dependent_with_just_one_parent() { await InitializeAsync(OnModelCreating); @@ -548,10 +550,83 @@ public virtual async Task Optional_dependent_materialized_when_no_properties() } } + [ConditionalFact] + public virtual async Task Warn_when_save_optional_dependent_with_null_values_sensitive() + { + await InitializeSharedAsync(OnSharedModelCreating); + + var meterReading = new MeterReading + { + MeterReadingDetails = new MeterReadingDetail() + }; + + using var context = CreateSharedContext(); + context.Add(meterReading); + + context.SaveChanges(); + + var expected = RelationalResources.LogOptionalDependentWithAllNullPropertiesSensitive(new TestLogger()).GenerateMessage(nameof(MeterReadingDetail), "{Id: -2147482647}"); + + var log = TestSqlLoggerFactory.Log.Single(l => l.Level == Extensions.Logging.LogLevel.Warning); + + Assert.Equal(expected, log.Message); + } + + [ConditionalFact] + public virtual async Task Warn_when_save_optional_dependent_with_null_values() + { + await InitializeSharedAsync(OnSharedModelCreating, sensitiveLogEnabled: false); + + var meterReading = new MeterReading + { + MeterReadingDetails = new MeterReadingDetail() + }; + + using var context = CreateSharedContext(); + context.Add(meterReading); + + TestSqlLoggerFactory.Clear(); + + context.SaveChanges(); + + var expected = RelationalResources.LogOptionalDependentWithAllNullProperties(new TestLogger()).GenerateMessage(nameof(MeterReadingDetail)); + + var log = TestSqlLoggerFactory.Log.Single(l => l.Level == Extensions.Logging.LogLevel.Warning); + + Assert.Equal(expected, log.Message); + } + + [ConditionalFact] + public virtual async Task No_warn_when_save_optional_dependent_at_least_one_none_null() + { + await InitializeSharedAsync(OnSharedModelCreating, sensitiveLogEnabled: false); + + using var context = CreateSharedContext(); + + var meterReading = new MeterReading + { + MeterReadingDetails = new MeterReadingDetail() + { + CurrentRead = "100" + } + }; + + context.Add(meterReading); + + TestSqlLoggerFactory.Clear(); + + context.SaveChanges(); + + var log = TestSqlLoggerFactory.Log.SingleOrDefault(l => l.Level == Extensions.Logging.LogLevel.Warning); + + Assert.Null(log.Message); + } + protected override string StoreName { get; } = "TableSplittingTest"; protected TestSqlLoggerFactory TestSqlLoggerFactory => (TestSqlLoggerFactory)ListLoggerFactory; protected ContextFactory ContextFactory { get; private set; } + protected ContextFactory SharedContextFactory { get; private set; } protected void AssertSql(params string[] expected) => TestSqlLoggerFactory.AssertBaseline(expected); @@ -574,20 +649,88 @@ protected virtual void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity().ToTable("Vehicles"); } + protected virtual void OnSharedModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity( + dob => + { + dob.ToTable("MeterReadings"); + dob.Property(o => o.ReadingStatus).HasColumnName("ReadingStatus"); + }); + modelBuilder.Entity( + ob => + { + ob.ToTable("MeterReadings"); + ob.Property(o => o.ReadingStatus).HasColumnName("ReadingStatus"); + ob.HasOne(o => o.MeterReadingDetails).WithOne() + .HasForeignKey(o => o.Id); + }); + } + protected async Task InitializeAsync(Action onModelCreating, bool seed = true) { ContextFactory = await InitializeAsync( onModelCreating, shouldLogCategory: _ => true, seed: seed ? c => c.Seed() : null); } + protected async Task InitializeSharedAsync(Action onModelCreating, bool sensitiveLogEnabled = true) + { + SharedContextFactory = await InitializeAsync( + onModelCreating, + shouldLogCategory: _ => true, + onConfiguring: options => + { + options.ConfigureWarnings(w => w.Log(RelationalEventId.OptionalDependentWithAllNullPropertiesWarning)) + .ConfigureWarnings(w => w.Log(RelationalEventId.OptionalDependentWithoutIdentifyingPropertyWarning)) + .EnableSensitiveDataLogging(sensitiveLogEnabled); + } + ); + } + protected virtual TransportationContext CreateContext() => ContextFactory.CreateContext(); + protected virtual SharedTableContext CreateSharedContext() + => SharedContextFactory.CreateContext(); + public override void Dispose() { base.Dispose(); ContextFactory = null; + SharedContextFactory = null; + } + + protected class SharedTableContext : PoolableDbContext + { + public SharedTableContext(DbContextOptions options) + : base(options) + { + } + + protected DbSet MeterReadings { get; set; } + protected DbSet MeterReadingDetails { get; set; } + } + + protected class MeterReading + { + public int Id { get; set; } + public MeterReadingStatus? ReadingStatus { get; set; } + public MeterReadingDetail MeterReadingDetails { get; set; } + } + + protected class MeterReadingDetail + { + public int Id { get; set; } + public MeterReadingStatus? ReadingStatus { get; set; } + public string CurrentRead { get; set; } + public string PreviousRead { get; set; } + } + + protected enum MeterReadingStatus + { + Running = 0, + NotAccesible = 2 } } } diff --git a/test/EFCore.Relational.Tests/RelationalEventIdTest.cs b/test/EFCore.Relational.Tests/RelationalEventIdTest.cs index 54f4cab0470..2debbd0c950 100644 --- a/test/EFCore.Relational.Tests/RelationalEventIdTest.cs +++ b/test/EFCore.Relational.Tests/RelationalEventIdTest.cs @@ -47,6 +47,7 @@ public void Every_eventId_has_a_logger_method_and_logs_when_level_enabled() var foreignKey = new ForeignKey(new List { property }, key, entityType, entityType, ConfigurationSource.Convention); var index = new Index(new List { property }, "IndexName", entityType, ConfigurationSource.Convention); var contextServices = RelationalTestHelpers.Instance.CreateContextServices(model.FinalizeModel()); + var updateEntry = new InternalEntityEntry(contextServices.GetRequiredService(), entityType, new object()); var fakeFactories = new Dictionary> { @@ -81,7 +82,8 @@ public void Every_eventId_has_a_logger_method_and_logs_when_level_enabled() { typeof(Type), () => typeof(object) }, { typeof(ValueConverter), () => new BoolToZeroOneConverter() }, { typeof(DbContext), () => new FakeDbContext() }, - { typeof(SqlExpression), () => new FakeSqlExpression() } + { typeof(SqlExpression), () => new FakeSqlExpression() }, + { typeof(IUpdateEntry), () => updateEntry} }; TestEventLogging( diff --git a/test/EFCore.Relational.Tests/TestUtilities/FakeModificationCommand.cs b/test/EFCore.Relational.Tests/TestUtilities/FakeModificationCommand.cs index cf843a1b695..e47823d8192 100644 --- a/test/EFCore.Relational.Tests/TestUtilities/FakeModificationCommand.cs +++ b/test/EFCore.Relational.Tests/TestUtilities/FakeModificationCommand.cs @@ -15,7 +15,7 @@ public FakeModificationCommand( Func generateParameterName, bool sensitiveLoggingEnabled, IReadOnlyList columnModifications) - : base(name, schema, generateParameterName, sensitiveLoggingEnabled, null) + : base(name, schema, generateParameterName, sensitiveLoggingEnabled, null, null) { ColumnModifications = columnModifications; } diff --git a/test/EFCore.Relational.Tests/Update/ModificationCommandComparerTest.cs b/test/EFCore.Relational.Tests/Update/ModificationCommandComparerTest.cs index 7df9e5fd0b7..0ded5a1f2fe 100644 --- a/test/EFCore.Relational.Tests/Update/ModificationCommandComparerTest.cs +++ b/test/EFCore.Relational.Tests/Update/ModificationCommandComparerTest.cs @@ -35,19 +35,19 @@ public void Compare_returns_0_only_for_commands_that_are_equal() var entry1 = stateManager.GetOrCreateEntry(new object()); entry1[(IProperty)key] = 1; entry1.SetEntityState(EntityState.Added); - var modificationCommandAdded = new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null); + var modificationCommandAdded = new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null, null); modificationCommandAdded.AddEntry(entry1, true); var entry2 = stateManager.GetOrCreateEntry(new object()); entry2[(IProperty)key] = 2; entry2.SetEntityState(EntityState.Modified); - var modificationCommandModified = new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null); + var modificationCommandModified = new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null, null); modificationCommandModified.AddEntry(entry2, true); var entry3 = stateManager.GetOrCreateEntry(new object()); entry3[(IProperty)key] = 3; entry3.SetEntityState(EntityState.Deleted); - var modificationCommandDeleted = new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null); + var modificationCommandDeleted = new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null, null); modificationCommandDeleted.AddEntry(entry3, true); var mCC = new ModificationCommandComparer(); @@ -57,44 +57,44 @@ public void Compare_returns_0_only_for_commands_that_are_equal() Assert.True( 0 == mCC.Compare( - new ModificationCommand("A", "dbo", new ParameterNameGenerator().GenerateNext, false, null), - new ModificationCommand("A", "dbo", new ParameterNameGenerator().GenerateNext, false, null))); + new ModificationCommand("A", "dbo", new ParameterNameGenerator().GenerateNext, false, null, null), + new ModificationCommand("A", "dbo", new ParameterNameGenerator().GenerateNext, false, null, null))); - Assert.True(0 > mCC.Compare(null, new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null))); - Assert.True(0 < mCC.Compare(new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null), null)); + Assert.True(0 > mCC.Compare(null, new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null, null))); + Assert.True(0 < mCC.Compare(new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null, null), null)); Assert.True( 0 > mCC.Compare( - new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null), - new ModificationCommand("A", "dbo", new ParameterNameGenerator().GenerateNext, false, null))); + new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null, null), + new ModificationCommand("A", "dbo", new ParameterNameGenerator().GenerateNext, false, null, null))); Assert.True( 0 < mCC.Compare( - new ModificationCommand("A", "dbo", new ParameterNameGenerator().GenerateNext, false, null), - new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null))); + new ModificationCommand("A", "dbo", new ParameterNameGenerator().GenerateNext, false, null, null), + new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null, null))); Assert.True( 0 > mCC.Compare( - new ModificationCommand("A", "dbo", new ParameterNameGenerator().GenerateNext, false, null), - new ModificationCommand("A", "foo", new ParameterNameGenerator().GenerateNext, false, null))); + new ModificationCommand("A", "dbo", new ParameterNameGenerator().GenerateNext, false, null, null), + new ModificationCommand("A", "foo", new ParameterNameGenerator().GenerateNext, false, null, null))); Assert.True( 0 < mCC.Compare( - new ModificationCommand("A", "foo", new ParameterNameGenerator().GenerateNext, false, null), - new ModificationCommand("A", "dbo", new ParameterNameGenerator().GenerateNext, false, null))); + new ModificationCommand("A", "foo", new ParameterNameGenerator().GenerateNext, false, null, null), + new ModificationCommand("A", "dbo", new ParameterNameGenerator().GenerateNext, false, null, null))); Assert.True( 0 > mCC.Compare( - new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null), - new ModificationCommand("B", null, new ParameterNameGenerator().GenerateNext, false, null))); + new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null, null), + new ModificationCommand("B", null, new ParameterNameGenerator().GenerateNext, false, null, null))); Assert.True( 0 < mCC.Compare( - new ModificationCommand("B", null, new ParameterNameGenerator().GenerateNext, false, null), - new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null))); + new ModificationCommand("B", null, new ParameterNameGenerator().GenerateNext, false, null, null), + new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null, null))); Assert.True(0 > mCC.Compare(modificationCommandModified, modificationCommandAdded)); Assert.True(0 < mCC.Compare(modificationCommandAdded, modificationCommandModified)); @@ -178,16 +178,16 @@ private void Compare_returns_0_only_for_entries_that_have_same_key_values_generi var entry1 = stateManager.GetOrCreateEntry(new object()); entry1[(IProperty)keyProperty] = value1; entry1.SetEntityState(EntityState.Modified); - var modificationCommand1 = new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null); + var modificationCommand1 = new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null, null); modificationCommand1.AddEntry(entry1, true); var entry2 = stateManager.GetOrCreateEntry(new object()); entry2[(IProperty)keyProperty] = value2; entry2.SetEntityState(EntityState.Modified); - var modificationCommand2 = new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null); + var modificationCommand2 = new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null, null); modificationCommand2.AddEntry(entry2, true); - var modificationCommand3 = new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null); + var modificationCommand3 = new ModificationCommand("A", null, new ParameterNameGenerator().GenerateNext, false, null, null); modificationCommand3.AddEntry(entry1, true); var mCC = new ModificationCommandComparer(); diff --git a/test/EFCore.Relational.Tests/Update/ModificationCommandTest.cs b/test/EFCore.Relational.Tests/Update/ModificationCommandTest.cs index 18a5018d6e2..09822f6f29c 100644 --- a/test/EFCore.Relational.Tests/Update/ModificationCommandTest.cs +++ b/test/EFCore.Relational.Tests/Update/ModificationCommandTest.cs @@ -22,7 +22,7 @@ public void ModificationCommand_initialized_correctly_for_added_entities_with_te var entry = CreateEntry(EntityState.Added, generateKeyValues: true); entry.SetTemporaryValue(entry.EntityType.FindPrimaryKey().Properties[0], -1); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.Equal("T1", command.TableName); @@ -66,7 +66,7 @@ public void ModificationCommand_initialized_correctly_for_added_entities_with_no { var entry = CreateEntry(EntityState.Added, generateKeyValues: true); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.Equal("T1", command.TableName); @@ -110,7 +110,7 @@ public void ModificationCommand_initialized_correctly_for_added_entities_with_ex { var entry = CreateEntry(EntityState.Added); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.Equal("T1", command.TableName); @@ -154,7 +154,7 @@ public void ModificationCommand_initialized_correctly_for_modified_entities_with { var entry = CreateEntry(EntityState.Modified, generateKeyValues: true); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.Equal("T1", command.TableName); @@ -198,7 +198,7 @@ public void ModificationCommand_initialized_correctly_for_modified_entities_with { var entry = CreateEntry(EntityState.Modified); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.Equal("T1", command.TableName); @@ -242,7 +242,7 @@ public void ModificationCommand_initialized_correctly_for_modified_entities_with { var entry = CreateEntry(EntityState.Modified, computeNonKeyValue: true); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.Equal("T1", command.TableName); @@ -286,7 +286,7 @@ public void ModificationCommand_initialized_correctly_for_deleted_entities() { var entry = CreateEntry(EntityState.Deleted); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.Equal("T1", command.TableName); @@ -310,7 +310,7 @@ public void ModificationCommand_initialized_correctly_for_deleted_entities_with_ { var entry = CreateEntry(EntityState.Deleted, computeNonKeyValue: true); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.Equal("T1", command.TableName); @@ -356,7 +356,7 @@ public void ModificationCommand_throws_for_unchanged_entities(bool sensitive) { var entry = CreateEntry(EntityState.Unchanged); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, sensitive, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, sensitive, null, null); Assert.Equal( sensitive @@ -372,7 +372,7 @@ public void ModificationCommand_throws_for_unknown_entities(bool sensitive) { var entry = CreateEntry(EntityState.Detached); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, sensitive, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, sensitive, null, null); Assert.Equal( sensitive @@ -387,7 +387,7 @@ public void RequiresResultPropagation_false_for_Delete_operation() var entry = CreateEntry( EntityState.Deleted, generateKeyValues: true, computeNonKeyValue: true); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.False(command.RequiresResultPropagation); @@ -399,7 +399,7 @@ public void RequiresResultPropagation_true_for_Insert_operation_if_store_generat var entry = CreateEntry( EntityState.Added, generateKeyValues: true, computeNonKeyValue: true); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.True(command.RequiresResultPropagation); @@ -410,7 +410,7 @@ public void RequiresResultPropagation_false_for_Insert_operation_if_no_store_gen { var entry = CreateEntry(EntityState.Added); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.False(command.RequiresResultPropagation); @@ -422,7 +422,7 @@ public void RequiresResultPropagation_true_for_Update_operation_if_non_key_store var entry = CreateEntry( EntityState.Modified, generateKeyValues: true, computeNonKeyValue: true); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.True(command.RequiresResultPropagation); @@ -433,7 +433,7 @@ public void RequiresResultPropagation_false_for_Update_operation_if_no_non_key_s { var entry = CreateEntry(EntityState.Modified, generateKeyValues: true); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null); command.AddEntry(entry, true); Assert.False(command.RequiresResultPropagation); diff --git a/test/EFCore.Relational.Tests/Update/ReaderModificationCommandBatchTest.cs b/test/EFCore.Relational.Tests/Update/ReaderModificationCommandBatchTest.cs index e48d087762a..0185a7866ca 100644 --- a/test/EFCore.Relational.Tests/Update/ReaderModificationCommandBatchTest.cs +++ b/test/EFCore.Relational.Tests/Update/ReaderModificationCommandBatchTest.cs @@ -27,7 +27,7 @@ public class ReaderModificationCommandBatchTest [ConditionalFact] public void AddCommand_adds_command_if_possible() { - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); var batch = new ModificationCommandBatchFake(); batch.AddCommand(command); @@ -44,7 +44,7 @@ public void AddCommand_adds_command_if_possible() [ConditionalFact] public void AddCommand_does_not_add_command_if_not_possible() { - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); var batch = new ModificationCommandBatchFake(); batch.AddCommand(command); @@ -60,7 +60,7 @@ public void AddCommand_does_not_add_command_if_not_possible() [ConditionalFact] public void AddCommand_does_not_add_command_if_resulting_sql_is_invalid() { - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); var batch = new ModificationCommandBatchFake(); batch.AddCommand(command); @@ -78,7 +78,7 @@ public void UpdateCommandText_compiles_inserts() { var entry = CreateEntry(EntityState.Added); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); command.AddEntry(entry, true); var fakeSqlGenerator = new FakeSqlGenerator( @@ -97,7 +97,7 @@ public void UpdateCommandText_compiles_updates() { var entry = CreateEntry(EntityState.Modified, generateKeyValues: true); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); command.AddEntry(entry, true); var fakeSqlGenerator = new FakeSqlGenerator( @@ -116,7 +116,7 @@ public void UpdateCommandText_compiles_deletes() { var entry = CreateEntry(EntityState.Deleted); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); command.AddEntry(entry, true); var fakeSqlGenerator = new FakeSqlGenerator( @@ -135,7 +135,7 @@ public void UpdateCommandText_compiles_multiple_commands() { var entry = CreateEntry(EntityState.Added); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); command.AddEntry(entry, true); var fakeSqlGenerator = new FakeSqlGenerator( @@ -154,7 +154,7 @@ public async Task ExecuteAsync_executes_batch_commands_and_consumes_reader() { var entry = CreateEntry(EntityState.Added); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); command.AddEntry(entry, true); var dbDataReader = CreateFakeDataReader(); @@ -176,7 +176,7 @@ public async Task ExecuteAsync_saves_store_generated_values() var entry = CreateEntry(EntityState.Added, generateKeyValues: true); entry.SetTemporaryValue(entry.EntityType.FindPrimaryKey().Properties[0], -1); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); command.AddEntry(entry, true); var connection = CreateConnection( @@ -199,7 +199,7 @@ public async Task ExecuteAsync_saves_store_generated_values_on_non_key_columns() EntityState.Added, generateKeyValues: true, computeNonKeyValue: true); entry.SetTemporaryValue(entry.EntityType.FindPrimaryKey().Properties[0], -1); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); command.AddEntry(entry, true); var connection = CreateConnection( @@ -221,7 +221,7 @@ public async Task ExecuteAsync_saves_store_generated_values_when_updating() var entry = CreateEntry( EntityState.Modified, generateKeyValues: true, computeNonKeyValue: true); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); command.AddEntry(entry, true); var connection = CreateConnection( @@ -243,7 +243,7 @@ public async Task Exception_not_thrown_for_more_than_one_row_returned_for_single var entry = CreateEntry(EntityState.Added, generateKeyValues: true); entry.SetTemporaryValue(entry.EntityType.FindPrimaryKey().Properties[0], -1); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); command.AddEntry(entry, true); var connection = CreateConnection( @@ -264,7 +264,7 @@ public async Task Exception_thrown_if_rows_returned_for_command_without_store_ge { var entry = CreateEntry(EntityState.Added); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); command.AddEntry(entry, true); var connection = CreateConnection( @@ -286,7 +286,7 @@ public async Task Exception_thrown_if_no_rows_returned_for_command_with_store_ge var entry = CreateEntry(EntityState.Added, generateKeyValues: true); entry.SetTemporaryValue(entry.EntityType.FindPrimaryKey().Properties[0], -1); - var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null); + var command = new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null, null); command.AddEntry(entry, true); var connection = CreateConnection( diff --git a/test/EFCore.SqlServer.Tests/Update/SqlServerModificationCommandBatchFactoryTest.cs b/test/EFCore.SqlServer.Tests/Update/SqlServerModificationCommandBatchFactoryTest.cs index f879f27056d..9072c535dc7 100644 --- a/test/EFCore.SqlServer.Tests/Update/SqlServerModificationCommandBatchFactoryTest.cs +++ b/test/EFCore.SqlServer.Tests/Update/SqlServerModificationCommandBatchFactoryTest.cs @@ -46,8 +46,8 @@ public void Uses_MaxBatchSize_specified_in_SqlServerOptionsExtension() var batch = factory.Create(); - Assert.True(batch.AddCommand(new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null))); - Assert.False(batch.AddCommand(new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null))); + Assert.True(batch.AddCommand(new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null))); + Assert.False(batch.AddCommand(new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null))); } [ConditionalFact] @@ -83,8 +83,8 @@ public void MaxBatchSize_is_optional() var batch = factory.Create(); - Assert.True(batch.AddCommand(new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null))); - Assert.True(batch.AddCommand(new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null))); + Assert.True(batch.AddCommand(new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null))); + Assert.True(batch.AddCommand(new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null))); } private class FakeDbContext : DbContext diff --git a/test/EFCore.SqlServer.Tests/Update/SqlServerModificationCommandBatchTest.cs b/test/EFCore.SqlServer.Tests/Update/SqlServerModificationCommandBatchTest.cs index c75d0c7ef45..c5fb7b5687f 100644 --- a/test/EFCore.SqlServer.Tests/Update/SqlServerModificationCommandBatchTest.cs +++ b/test/EFCore.SqlServer.Tests/Update/SqlServerModificationCommandBatchTest.cs @@ -43,10 +43,10 @@ public void AddCommand_returns_false_when_max_batch_size_is_reached() Assert.True( batch.AddCommand( - new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null))); + new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null))); Assert.False( batch.AddCommand( - new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null))); + new ModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, false, null, null))); } private class FakeDbContext : DbContext