-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SqlServerValueGenerationStrategy which conflicts now causes warning (#…
…19887) A SqlServerValueGenerationStrategy which conflicts with another value generation strategy now causes a warning instead of an error. The warning throws by default but that can be overridden if wanted.
- Loading branch information
Showing
11 changed files
with
370 additions
and
14 deletions.
There are no files selected for viewing
53 changes: 53 additions & 0 deletions
53
src/EFCore.SqlServer/Diagnostics/ConflictingValueGenerationStrategiesEventData.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// 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 JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Metadata; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Diagnostics | ||
{ | ||
/// <summary> | ||
/// A <see cref="DiagnosticSource" /> event payload class for events that have | ||
/// a property. | ||
/// </summary> | ||
public class ConflictingValueGenerationStrategiesEventData : EventData | ||
{ | ||
/// <summary> | ||
/// Constructs the event payload. | ||
/// </summary> | ||
/// <param name="eventDefinition"> The event definition. </param> | ||
/// <param name="messageGenerator"> A delegate that generates a log message for this event. </param> | ||
/// <param name="sqlServerValueGenerationStrategy"> The SQL Server value generation strategy. </param> | ||
/// <param name="otherValueGenerationStrategy"> The other value generation strategy. </param> | ||
/// <param name="property"> The property. </param> | ||
public ConflictingValueGenerationStrategiesEventData( | ||
[NotNull] EventDefinitionBase eventDefinition, | ||
[NotNull] Func<EventDefinitionBase, EventData, string> messageGenerator, | ||
SqlServerValueGenerationStrategy sqlServerValueGenerationStrategy, | ||
[NotNull] string otherValueGenerationStrategy, | ||
[NotNull] IProperty property) | ||
: base(eventDefinition, messageGenerator) | ||
{ | ||
SqlServerValueGenerationStrategy = sqlServerValueGenerationStrategy; | ||
OtherValueGenerationStrategy = otherValueGenerationStrategy; | ||
Property = property; | ||
} | ||
|
||
/// <summary> | ||
/// The SQL Server value generation strategy. | ||
/// </summary> | ||
public virtual SqlServerValueGenerationStrategy SqlServerValueGenerationStrategy { get; } | ||
|
||
/// <summary> | ||
/// The other value generation strategy. | ||
/// </summary> | ||
public virtual string OtherValueGenerationStrategy { get; } | ||
|
||
/// <summary> | ||
/// The property. | ||
/// </summary> | ||
public virtual IProperty Property { get; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
150 changes: 150 additions & 0 deletions
150
test/EFCore.SqlServer.FunctionalTests/SqlServerValueGenerationConflictTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
// 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.Linq; | ||
using Microsoft.EntityFrameworkCore.Diagnostics; | ||
using Microsoft.EntityFrameworkCore.Infrastructure; | ||
using Microsoft.EntityFrameworkCore.Metadata; | ||
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; | ||
using Microsoft.EntityFrameworkCore.SqlServer.Diagnostics.Internal; | ||
using Microsoft.EntityFrameworkCore.SqlServer.Internal; | ||
using Microsoft.EntityFrameworkCore.TestUtilities; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Logging; | ||
using Xunit; | ||
|
||
// ReSharper disable InconsistentNaming | ||
namespace Microsoft.EntityFrameworkCore | ||
{ | ||
public class SqlServerValueGenerationStrategyThrowTest : | ||
SqlServerValueGenerationConflictTest<SqlServerValueGenerationStrategyThrowTest.ThrowContext> | ||
{ | ||
public SqlServerValueGenerationStrategyThrowTest( | ||
SqlServerValueGenerationStrategyFixture<ThrowContext> fixture) | ||
: base(fixture) | ||
{ | ||
} | ||
|
||
[ConditionalFact] | ||
public virtual void SqlServerValueGeneration_conflicting_with_existing_ValueGeneration_strategy_throws() | ||
{ | ||
var modelBuilder = CreateModelBuilder(); | ||
modelBuilder.Entity<Fred>() | ||
.Property(e => e.Id) | ||
.HasDefaultValueSql("2") | ||
.UseHiLo(); | ||
|
||
Assert.Equal( | ||
CoreStrings.WarningAsErrorTemplate( | ||
SqlServerEventId.ConflictingValueGenerationStrategiesWarning, | ||
SqlServerResources.LogConflictingValueGenerationStrategies( | ||
new TestLogger<SqlServerLoggingDefinitions>()) | ||
.GenerateMessage(SqlServerValueGenerationStrategy.SequenceHiLo.ToString(), "DefaultValueSql", "Id", nameof(Fred)), | ||
"SqlServerEventId.ConflictingValueGenerationStrategiesWarning"), | ||
Assert.Throws<InvalidOperationException>(() => Validate(modelBuilder)).Message); | ||
} | ||
|
||
public class ThrowContext : DbContext | ||
{ | ||
public ThrowContext(DbContextOptions options) | ||
: base(options) | ||
{ | ||
} | ||
|
||
public virtual DbSet<Fred> Freds { get; set; } | ||
|
||
// use the normal behavior of ConflictingValueGenerationStrategiesWarning | ||
// defined in UseSqlServer() | ||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) | ||
=> optionsBuilder.UseSqlServer(); | ||
} | ||
} | ||
|
||
public class SqlServerValueGenerationStrategyNoThrowTest : | ||
SqlServerValueGenerationConflictTest<SqlServerValueGenerationStrategyNoThrowTest.NoThrowContext> | ||
{ | ||
public SqlServerValueGenerationStrategyNoThrowTest( | ||
SqlServerValueGenerationStrategyFixture<NoThrowContext> fixture) | ||
: base(fixture) | ||
{ | ||
} | ||
|
||
[ConditionalFact] | ||
public virtual void SqlServerValueGeneration_conflicting_with_existing_ValueGeneration_strategy_warns() | ||
{ | ||
var modelBuilder = CreateModelBuilder(); | ||
modelBuilder.Entity<Fred>() | ||
.Property(e => e.Id) | ||
.HasDefaultValueSql("2") | ||
.UseHiLo(); | ||
|
||
// Assert - this does not throw | ||
Validate(modelBuilder); | ||
|
||
var logEntry = Fixture.ListLoggerFactory.Log.Single( | ||
l => l.Level == LogLevel.Warning && l.Id == SqlServerEventId.ConflictingValueGenerationStrategiesWarning); | ||
Assert.Equal(SqlServerResources.LogConflictingValueGenerationStrategies( | ||
new TestLogger<SqlServerLoggingDefinitions>()) | ||
.GenerateMessage(SqlServerValueGenerationStrategy.SequenceHiLo.ToString(), "DefaultValueSql", "Id", nameof(Fred)), | ||
logEntry.Message); | ||
} | ||
|
||
public class NoThrowContext : DbContext | ||
{ | ||
public NoThrowContext(DbContextOptions options) : base(options) | ||
{ | ||
} | ||
|
||
public virtual DbSet<Fred> Freds { get; set; } | ||
|
||
// override the normal behavior of ConflictingValueGenerationStrategiesWarning | ||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) | ||
=> optionsBuilder | ||
.UseSqlServer() | ||
.ConfigureWarnings( | ||
b => b.Log(SqlServerEventId.ConflictingValueGenerationStrategiesWarning)); | ||
} | ||
} | ||
|
||
public class SqlServerValueGenerationConflictTest<TContext> | ||
: IClassFixture<SqlServerValueGenerationStrategyFixture<TContext>> | ||
where TContext : DbContext | ||
{ | ||
public SqlServerValueGenerationConflictTest(SqlServerValueGenerationStrategyFixture<TContext> fixture) | ||
=> Fixture = fixture; | ||
|
||
protected SqlServerValueGenerationStrategyFixture<TContext> Fixture { get; } | ||
|
||
public TContext CreateContext() => (TContext)Fixture.CreateContext(); | ||
|
||
protected virtual ModelBuilder CreateModelBuilder() | ||
{ | ||
var conventionSet = CreateConventionSetBuilder(CreateContext()).CreateConventionSet(); | ||
|
||
return new ModelBuilder(conventionSet); | ||
} | ||
|
||
protected virtual IConventionSetBuilder CreateConventionSetBuilder(DbContext context) | ||
=> context.GetService<IConventionSetBuilder>(); | ||
|
||
protected virtual IModel Validate(ModelBuilder modelBuilder) | ||
=> modelBuilder.FinalizeModel(); | ||
|
||
public class Fred | ||
{ | ||
public int Id { get; set; } | ||
} | ||
} | ||
|
||
public class SqlServerValueGenerationStrategyFixture<TContext> : SharedStoreFixtureBase<DbContext> | ||
where TContext : DbContext | ||
{ | ||
protected override string StoreName { get; } = "SqlServerValueGenerationStrategy"; | ||
protected override Type ContextType { get; } = typeof(TContext); | ||
protected override ITestStoreFactory TestStoreFactory => SqlServerTestStoreFactory.Instance; | ||
protected override bool ShouldLogCategory(string logCategory) | ||
=> logCategory == DbLoggerCategory.Model.Validation.Name; | ||
protected override bool UsePooling => false; | ||
} | ||
} |
Oops, something went wrong.