diff --git a/src/EFCore.Relational/Diagnostics/RelationalEventId.cs b/src/EFCore.Relational/Diagnostics/RelationalEventId.cs
index c05c73c46a3..0b1f48c5275 100644
--- a/src/EFCore.Relational/Diagnostics/RelationalEventId.cs
+++ b/src/EFCore.Relational/Diagnostics/RelationalEventId.cs
@@ -81,6 +81,7 @@ private enum Id
NonTransactionalMigrationOperationWarning,
AcquiringMigrationLock,
MigrationsUserTransactionWarning,
+ ModelSnapshotNotFound,
// Query events
QueryClientEvaluationWarning = CoreEventId.RelationalBaseId + 500,
@@ -778,6 +779,19 @@ private static EventId MakeMigrationsId(Id id)
///
public static readonly EventId MigrationsUserTransactionWarning = MakeMigrationsId(Id.MigrationsUserTransactionWarning);
+ ///
+ /// Model snapshot was not found.
+ ///
+ ///
+ ///
+ /// This event is in the category.
+ ///
+ ///
+ /// This event uses the payload when used with a .
+ ///
+ ///
+ public static readonly EventId ModelSnapshotNotFound = MakeMigrationsId(Id.ModelSnapshotNotFound);
+
private static readonly string _queryPrefix = DbLoggerCategory.Query.Name + ".";
private static EventId MakeQueryId(Id id)
diff --git a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
index 177b7e90bba..acecc79ca01 100644
--- a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
+++ b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs
@@ -2343,6 +2343,77 @@ private static string PendingModelChanges(EventDefinitionBase definition, EventD
return d.GenerateMessage(p.ContextType.ShortDisplayName());
}
+ ///
+ /// Logs for the event.
+ ///
+ /// The diagnostics logger to use.
+ /// The type being used.
+ public static void NonDeterministicModel(
+ this IDiagnosticsLogger diagnostics,
+ Type contextType)
+ {
+ var definition = RelationalResources.LogNonDeterministicModel(diagnostics);
+
+ if (diagnostics.ShouldLog(definition))
+ {
+ definition.Log(diagnostics, contextType.ShortDisplayName());
+ }
+
+ if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ var eventData = new DbContextTypeEventData(
+ definition,
+ NonDeterministicModel,
+ contextType);
+
+ diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+ }
+ }
+
+ private static string NonDeterministicModel(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (DbContextTypeEventData)payload;
+ return d.GenerateMessage(p.ContextType.ShortDisplayName());
+ }
+
+ ///
+ /// Logs for the event.
+ ///
+ /// The diagnostics logger to use.
+ /// The migrator.
+ /// The assembly in which migrations are stored.
+ public static void ModelSnapshotNotFound(
+ this IDiagnosticsLogger diagnostics,
+ IMigrator migrator,
+ IMigrationsAssembly migrationsAssembly)
+ {
+ var definition = RelationalResources.LogNoModelSnapshotFound(diagnostics);
+
+ if (diagnostics.ShouldLog(definition))
+ {
+ definition.Log(diagnostics, migrationsAssembly.Assembly.GetName().Name!);
+ }
+
+ if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled))
+ {
+ var eventData = new MigrationAssemblyEventData(
+ definition,
+ ModelSnapshotNotFound,
+ migrator,
+ migrationsAssembly);
+
+ diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled);
+ }
+ }
+
+ private static string ModelSnapshotNotFound(EventDefinitionBase definition, EventData payload)
+ {
+ var d = (EventDefinition)definition;
+ var p = (MigrationAssemblyEventData)payload;
+ return d.GenerateMessage(p.MigrationsAssembly.Assembly.GetName().Name!);
+ }
+
///
/// Logs for the event.
///
diff --git a/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs b/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs
index 762172c8944..9634f027bf7 100644
--- a/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs
+++ b/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs
@@ -374,7 +374,7 @@ public abstract class RelationalLoggingDefinitions : LoggingDefinitions
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
[EntityFrameworkInternal]
- public EventDefinitionBase? LogMigrationsUserTransactionWarning;
+ public EventDefinitionBase? LogMigrationsUserTransaction;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -673,6 +673,24 @@ public abstract class RelationalLoggingDefinitions : LoggingDefinitions
[EntityFrameworkInternal]
public EventDefinitionBase? LogPendingModelChanges;
+ ///
+ /// 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? LogNonDeterministicModel;
+
+ ///
+ /// 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? LogNoModelSnapshotFound;
+
///
/// 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
diff --git a/src/EFCore.Relational/Migrations/Internal/Migrator.cs b/src/EFCore.Relational/Migrations/Internal/Migrator.cs
index 4380d89fd82..ea758d2c634 100644
--- a/src/EFCore.Relational/Migrations/Internal/Migrator.cs
+++ b/src/EFCore.Relational/Migrations/Internal/Migrator.cs
@@ -3,6 +3,7 @@
using System.Transactions;
using Microsoft.EntityFrameworkCore.Diagnostics.Internal;
+using Microsoft.EntityFrameworkCore.Metadata.Internal;
namespace Microsoft.EntityFrameworkCore.Migrations.Internal;
@@ -93,24 +94,7 @@ public Migrator(
public virtual void Migrate(string? targetMigration)
{
var useTransaction = _connection.CurrentTransaction is null;
- if (!useTransaction
- && _executionStrategy.RetriesOnFailure)
- {
- throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction);
- }
-
- if (RelationalResources.LogPendingModelChanges(_logger).WarningBehavior != WarningBehavior.Ignore
- && HasPendingModelChanges())
- {
- _logger.PendingModelChangesWarning(_currentContext.Context.GetType());
- }
-
- if (!useTransaction)
- {
- _logger.MigrationsUserTransactionWarning();
- }
-
- _logger.MigrateUsingConnection(this, _connection);
+ ValidateMigrations(useTransaction);
using var transactionScope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled);
@@ -235,24 +219,7 @@ public virtual async Task MigrateAsync(
CancellationToken cancellationToken = default)
{
var useTransaction = _connection.CurrentTransaction is null;
- if (!useTransaction
- && _executionStrategy.RetriesOnFailure)
- {
- throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction);
- }
-
- if (RelationalResources.LogPendingModelChanges(_logger).WarningBehavior != WarningBehavior.Ignore
- && HasPendingModelChanges())
- {
- _logger.PendingModelChangesWarning(_currentContext.Context.GetType());
- }
-
- if (!useTransaction)
- {
- _logger.MigrationsUserTransactionWarning();
- }
-
- _logger.MigrateUsingConnection(this, _connection);
+ ValidateMigrations(useTransaction);
using var transactionScope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled);
@@ -382,6 +349,48 @@ await _migrationCommandExecutor.ExecuteNonQueryAsync(
}
}
+ private void ValidateMigrations(bool useTransaction)
+ {
+ if (!useTransaction
+ && _executionStrategy.RetriesOnFailure)
+ {
+ throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction);
+ }
+
+ if (_migrationsAssembly.Migrations.Count == 0)
+ {
+ _logger.MigrationsNotFound(this, _migrationsAssembly);
+ }
+ else if (_migrationsAssembly.ModelSnapshot == null)
+ {
+ _logger.ModelSnapshotNotFound(this, _migrationsAssembly);
+ }
+ else if (RelationalResources.LogPendingModelChanges(_logger).WarningBehavior != WarningBehavior.Ignore
+ && HasPendingModelChanges())
+ {
+ var modelSource = (ModelSource)_currentContext.Context.GetService();
+#pragma warning disable EF1001 // Internal EF Core API usage.
+ var newDesignTimeModel = modelSource.CreateModel(
+ _currentContext.Context, _currentContext.Context.GetService(), designTime: true);
+#pragma warning restore EF1001 // Internal EF Core API usage.
+ if (_migrationsModelDiffer.HasDifferences(newDesignTimeModel.GetRelationalModel(), _designTimeModel.Model.GetRelationalModel()))
+ {
+ _logger.NonDeterministicModel(_currentContext.Context.GetType());
+ }
+ else
+ {
+ _logger.PendingModelChangesWarning(_currentContext.Context.GetType());
+ }
+ }
+
+ if (!useTransaction)
+ {
+ _logger.MigrationsUserTransactionWarning();
+ }
+
+ _logger.MigrateUsingConnection(this, _connection);
+ }
+
private IEnumerable<(string, Func>)> GetMigrationCommandLists(MigratorData parameters)
{
var migrationsToApply = parameters.AppliedMigrations;
@@ -449,10 +458,6 @@ protected virtual void PopulateMigrations(
var appliedMigrations = new Dictionary();
var unappliedMigrations = new Dictionary();
var appliedMigrationEntrySet = new HashSet(appliedMigrationEntries, StringComparer.OrdinalIgnoreCase);
- if (_migrationsAssembly.Migrations.Count == 0)
- {
- _logger.MigrationsNotFound(this, _migrationsAssembly);
- }
foreach (var (key, typeInfo) in _migrationsAssembly.Migrations)
{
diff --git a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
index 731c62c4ec2..5bbbd42c9d0 100644
--- a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
+++ b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
@@ -3429,11 +3429,11 @@ public static EventDefinition LogMigrationAttributeMissingWarning(IDiagn
///
public static EventDefinition LogMigrationsUserTransaction(IDiagnosticsLogger logger)
{
- var definition = ((RelationalLoggingDefinitions)logger.Definitions).LogMigrationsUserTransactionWarning;
+ var definition = ((RelationalLoggingDefinitions)logger.Definitions).LogMigrationsUserTransaction;
if (definition == null)
{
definition = NonCapturingLazyInitializer.EnsureInitialized(
- ref ((RelationalLoggingDefinitions)logger.Definitions).LogMigrationsUserTransactionWarning,
+ ref ((RelationalLoggingDefinitions)logger.Definitions).LogMigrationsUserTransaction,
logger,
static logger => new EventDefinition(
logger.Options,
@@ -3572,7 +3572,7 @@ public static EventDefinition LogNoMigrationsApplied(IDiagnosticsLogger logger)
}
///
- /// No migrations were found in assembly '{migrationsAssembly}'.
+ /// No migrations were found in assembly '{migrationsAssembly}'. A migration needs to be added before the database can be updated.
///
public static EventDefinition LogNoMigrationsFound(IDiagnosticsLogger logger)
{
@@ -3585,7 +3585,7 @@ public static EventDefinition LogNoMigrationsFound(IDiagnosticsLogger lo
static logger => new EventDefinition(
logger.Options,
RelationalEventId.MigrationsNotFound,
- LogLevel.Debug,
+ LogLevel.Information,
"RelationalEventId.MigrationsNotFound",
level => LoggerMessage.Define(
level,
@@ -3596,6 +3596,56 @@ public static EventDefinition LogNoMigrationsFound(IDiagnosticsLogger lo
return (EventDefinition)definition;
}
+ ///
+ /// Model snapshot was not found in assembly '{migrationsAssembly}'. Skipping pending model changes check.
+ ///
+ public static EventDefinition LogNoModelSnapshotFound(IDiagnosticsLogger logger)
+ {
+ var definition = ((RelationalLoggingDefinitions)logger.Definitions).LogNoModelSnapshotFound;
+ if (definition == null)
+ {
+ definition = NonCapturingLazyInitializer.EnsureInitialized(
+ ref ((RelationalLoggingDefinitions)logger.Definitions).LogNoModelSnapshotFound,
+ logger,
+ static logger => new EventDefinition(
+ logger.Options,
+ RelationalEventId.ModelSnapshotNotFound,
+ LogLevel.Information,
+ "RelationalEventId.ModelSnapshotNotFound",
+ level => LoggerMessage.Define(
+ level,
+ RelationalEventId.ModelSnapshotNotFound,
+ _resourceManager.GetString("LogNoModelSnapshotFound")!)));
+ }
+
+ return (EventDefinition)definition;
+ }
+
+ ///
+ /// The model for context '{contextType}' changes each time it is built. This is usually caused by dynamic values used in a 'HasData' call (e.g. `new DateTime()`, `Guid.NewGuid()`). Add a new migration and examine its contents to locate the cause, and replace the dynamic call with a static, hardcoded value. See https://aka.ms/efcore-docs-pending-changes.
+ ///
+ public static EventDefinition LogNonDeterministicModel(IDiagnosticsLogger logger)
+ {
+ var definition = ((RelationalLoggingDefinitions)logger.Definitions).LogNonDeterministicModel;
+ if (definition == null)
+ {
+ definition = NonCapturingLazyInitializer.EnsureInitialized(
+ ref ((RelationalLoggingDefinitions)logger.Definitions).LogNonDeterministicModel,
+ logger,
+ static logger => new EventDefinition(
+ logger.Options,
+ RelationalEventId.PendingModelChangesWarning,
+ LogLevel.Error,
+ "RelationalEventId.PendingModelChangesWarning",
+ level => LoggerMessage.Define(
+ level,
+ RelationalEventId.PendingModelChangesWarning,
+ _resourceManager.GetString("LogNonDeterministicModel")!)));
+ }
+
+ return (EventDefinition)definition;
+ }
+
///
/// The migration operation '{operation}' from migration '{migration}' cannot be executed in a transaction. If the app is terminated or an unrecoverable error occurs while this operation is being executed then the migration will be left in a partially applied state and would need to be reverted manually before it can be applied again. Create a separate migration that contains just this operation.
///
@@ -3610,7 +3660,7 @@ public static EventDefinition LogNonTransactionalMigrationOperat
static logger => new EventDefinition(
logger.Options,
RelationalEventId.NonTransactionalMigrationOperationWarning,
- LogLevel.Error,
+ LogLevel.Warning,
"RelationalEventId.NonTransactionalMigrationOperationWarning",
level => LoggerMessage.Define(
level,
@@ -3747,7 +3797,7 @@ public static EventDefinition LogOptionalDependentWithoutIdentifyingProp
}
///
- /// The model for context '{contextType}' has pending changes. Add a new migration before updating the database.
+ /// The model for context '{contextType}' has pending changes. Add a new migration before updating the database. See https://aka.ms/efcore-docs-pending-changes.
///
public static EventDefinition LogPendingModelChanges(IDiagnosticsLogger logger)
{
diff --git a/src/EFCore.Relational/Properties/RelationalStrings.resx b/src/EFCore.Relational/Properties/RelationalStrings.resx
index 104daf9dafb..2382f648428 100644
--- a/src/EFCore.Relational/Properties/RelationalStrings.resx
+++ b/src/EFCore.Relational/Properties/RelationalStrings.resx
@@ -811,12 +811,20 @@
Information RelationalEventId.MigrationsNotApplied
- No migrations were found in assembly '{migrationsAssembly}'.
- Debug RelationalEventId.MigrationsNotFound string
+ No migrations were found in assembly '{migrationsAssembly}'. A migration needs to be added before the database can be updated.
+ Information RelationalEventId.MigrationsNotFound string
+
+
+ Model snapshot was not found in assembly '{migrationsAssembly}'. Skipping pending model changes check.
+ Information RelationalEventId.ModelSnapshotNotFound string
+
+
+ The model for context '{contextType}' changes each time it is built. This is usually caused by dynamic values used in a 'HasData' call (e.g. `new DateTime()`, `Guid.NewGuid()`). Add a new migration and examine its contents to locate the cause, and replace the dynamic call with a static, hardcoded value. See https://aka.ms/efcore-docs-pending-changes.
+ Error RelationalEventId.PendingModelChangesWarning string
The migration operation '{operation}' from migration '{migration}' cannot be executed in a transaction. If the app is terminated or an unrecoverable error occurs while this operation is being executed then the migration will be left in a partially applied state and would need to be reverted manually before it can be applied again. Create a separate migration that contains just this operation.
- Error RelationalEventId.NonTransactionalMigrationOperationWarning string string
+ Warning RelationalEventId.NonTransactionalMigrationOperationWarning string string
Opened connection to database '{database}' on server '{server}'.
@@ -839,7 +847,7 @@
Warning RelationalEventId.OptionalDependentWithoutIdentifyingPropertyWarning string
- The model for context '{contextType}' has pending changes. Add a new migration before updating the database.
+ The model for context '{contextType}' has pending changes. Add a new migration before updating the database. See https://aka.ms/efcore-docs-pending-changes.
Error RelationalEventId.PendingModelChangesWarning string
diff --git a/src/EFCore/Infrastructure/ModelSource.cs b/src/EFCore/Infrastructure/ModelSource.cs
index d1113d8bd27..e69a0e42e3a 100644
--- a/src/EFCore/Infrastructure/ModelSource.cs
+++ b/src/EFCore/Infrastructure/ModelSource.cs
@@ -65,11 +65,7 @@ public virtual IModel GetModel(
{
if (!cache.TryGetValue(cacheKey, out model))
{
- model = CreateModel(
- context, modelCreationDependencies.ConventionSetBuilder, modelCreationDependencies.ModelDependencies);
-
- var designTimeModel = modelCreationDependencies.ModelRuntimeInitializer.Initialize(
- model, designTime: true, modelCreationDependencies.ValidationLogger);
+ var designTimeModel = CreateModel(context, modelCreationDependencies, designTime: true);
var runtimeModel = (IModel)designTimeModel.FindRuntimeAnnotationValue(CoreAnnotationNames.ReadOnlyModel)!;
@@ -88,6 +84,23 @@ public virtual IModel GetModel(
return model!;
}
+ ///
+ /// 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 virtual IModel CreateModel(
+ DbContext context,
+ ModelCreationDependencies modelCreationDependencies,
+ bool designTime)
+ {
+ var model = CreateModel(context, modelCreationDependencies.ConventionSetBuilder, modelCreationDependencies.ModelDependencies);
+ return modelCreationDependencies.ModelRuntimeInitializer.Initialize(
+ model, designTime, modelCreationDependencies.ValidationLogger);
+ }
+
///
/// Creates the model. This method is called when the model was not found in the cache.
///
diff --git a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs
index d9216f9dfe5..ce667239197 100644
--- a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs
+++ b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs
@@ -8570,10 +8570,7 @@ protected CSharpMigrationsGenerator CreateMigrationsGenerator()
var sqlServerTypeMappingSource = new SqlServerTypeMappingSource(
TestServiceFactory.Instance.Create(),
new RelationalTypeMappingSourceDependencies(
- new IRelationalTypeMappingSourcePlugin[]
- {
- new SqlServerNetTopologySuiteTypeMappingSourcePlugin(NtsGeometryServices.Instance)
- }));
+ [new SqlServerNetTopologySuiteTypeMappingSourcePlugin(NtsGeometryServices.Instance)]));
var codeHelper = new CSharpHelper(sqlServerTypeMappingSource);
diff --git a/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsInfrastructureTestBase.cs b/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsInfrastructureTestBase.cs
index 25844386efa..a00f1c67989 100644
--- a/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsInfrastructureTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsInfrastructureTestBase.cs
@@ -154,8 +154,8 @@ public virtual void Can_apply_one_migration()
x => Assert.Equal("00000000000001_Migration1", x.MigrationId));
Assert.Equal(
- LogLevel.Error,
- Fixture.TestSqlLoggerFactory.Log.Single(l => l.Id == RelationalEventId.PendingModelChangesWarning).Level);
+ LogLevel.Information,
+ Fixture.TestSqlLoggerFactory.Log.Single(l => l.Id == RelationalEventId.ModelSnapshotNotFound).Level);
}
[ConditionalFact]
@@ -291,6 +291,10 @@ public virtual async Task Can_generate_no_migration_script()
using var db = Fixture.CreateEmptyContext();
var migrator = db.GetService();
+ await db.Database.EnsureDeletedAsync();
+ await GiveMeSomeTimeAsync(db);
+ await db.GetService().CreateAsync();
+
await SetAndExecuteSqlAsync(migrator.GenerateScript());
}
@@ -300,6 +304,10 @@ public virtual async Task Can_generate_migration_from_initial_database_to_initia
using var db = Fixture.CreateContext();
var migrator = db.GetService();
+ await db.Database.EnsureDeletedAsync();
+ await GiveMeSomeTimeAsync(db);
+ await db.GetService().CreateAsync();
+
await SetAndExecuteSqlAsync(migrator.GenerateScript(fromMigration: Migration.InitialDatabase, toMigration: Migration.InitialDatabase));
}
@@ -310,6 +318,7 @@ public virtual async Task Can_generate_up_and_down_scripts()
var migrator = db.GetService();
await db.Database.EnsureDeletedAsync();
+ await GiveMeSomeTimeAsync(db);
await db.GetService().CreateAsync();
await SetAndExecuteSqlAsync(migrator.GenerateScript());
@@ -327,6 +336,7 @@ public virtual async Task Can_generate_up_and_down_scripts_noTransactions()
var migrator = db.GetService();
await db.Database.EnsureDeletedAsync();
+ await GiveMeSomeTimeAsync(db);
await db.GetService().CreateAsync();
await SetAndExecuteSqlAsync(migrator.GenerateScript(options: MigrationsSqlGenerationOptions.NoTransactions));
@@ -345,6 +355,7 @@ public virtual async Task Can_generate_one_up_and_down_script()
var migrator = db.GetService();
await db.Database.EnsureDeletedAsync();
+ await GiveMeSomeTimeAsync(db);
await db.GetService().CreateAsync();
await ExecuteSqlAsync(migrator.GenerateScript(
@@ -367,6 +378,7 @@ public virtual async Task Can_generate_up_and_down_script_using_names()
var migrator = db.GetService();
await db.Database.EnsureDeletedAsync();
+ await GiveMeSomeTimeAsync(db);
await db.GetService().CreateAsync();
await ExecuteSqlAsync(migrator.GenerateScript(
@@ -389,6 +401,7 @@ public virtual async Task Can_generate_idempotent_up_and_down_scripts()
var migrator = db.GetService();
await db.Database.EnsureDeletedAsync();
+ await GiveMeSomeTimeAsync(db);
await db.GetService().CreateAsync();
await SetAndExecuteSqlAsync(migrator.GenerateScript(
@@ -409,6 +422,7 @@ public virtual async Task Can_generate_idempotent_up_and_down_scripts_noTransact
var migrator = db.GetService();
await db.Database.EnsureDeletedAsync();
+ await GiveMeSomeTimeAsync(db);
await db.GetService().CreateAsync();
await SetAndExecuteSqlAsync(migrator.GenerateScript(
diff --git a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs
index c4b8eb03ac8..491a5e86ab6 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs
@@ -8,6 +8,7 @@
using Microsoft.EntityFrameworkCore.Diagnostics.Internal;
using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal;
using Microsoft.EntityFrameworkCore.TestModels.AspNetIdentity;
+using static Microsoft.EntityFrameworkCore.Migrations.MigrationsInfrastructureFixtureBase;
// ReSharper disable InconsistentNaming
namespace Microsoft.EntityFrameworkCore.Migrations
@@ -650,12 +651,136 @@ public override void Can_get_active_provider()
Assert.Equal("Microsoft.EntityFrameworkCore.SqlServer", ActiveProvider);
}
+ [ConditionalFact]
+ public void Throws_when_no_migrations()
+ {
+ using var context = new DbContext(
+ Fixture.TestStore.AddProviderOptions(
+ new DbContextOptionsBuilder().EnableServiceProviderCaching(false)
+ .ConfigureWarnings(e => e.Throw(RelationalEventId.MigrationsNotFound))).Options);
+
+ context.Database.EnsureDeleted();
+ GiveMeSomeTime(context);
+
+ Assert.Equal(
+ CoreStrings.WarningAsErrorTemplate(
+ RelationalEventId.MigrationsNotFound.ToString(),
+ RelationalResources.LogNoMigrationsFound(new TestLogger())
+ .GenerateMessage(typeof(DbContext).Assembly.GetName().Name),
+ "RelationalEventId.MigrationsNotFound"),
+ (Assert.Throws(context.Database.Migrate)).Message);
+ }
+
+ [ConditionalFact]
+ public async Task Throws_when_no_migrations_async()
+ {
+ using var context = new DbContext(
+ Fixture.TestStore.AddProviderOptions(
+ new DbContextOptionsBuilder().EnableServiceProviderCaching(false)
+ .ConfigureWarnings(e => e.Throw(RelationalEventId.MigrationsNotFound))).Options);
+
+ await context.Database.EnsureDeletedAsync();
+ await GiveMeSomeTimeAsync(context);
+
+ Assert.Equal(
+ CoreStrings.WarningAsErrorTemplate(
+ RelationalEventId.MigrationsNotFound.ToString(),
+ RelationalResources.LogNoMigrationsFound(new TestLogger())
+ .GenerateMessage(typeof(DbContext).Assembly.GetName().Name),
+ "RelationalEventId.MigrationsNotFound"),
+ (await Assert.ThrowsAsync(() => context.Database.MigrateAsync())).Message);
+ }
+
+ [ConditionalFact]
+ public void Throws_when_no_snapshot()
+ {
+ using var context = new MigrationsContext(
+ Fixture.TestStore.AddProviderOptions(
+ new DbContextOptionsBuilder().EnableServiceProviderCaching(false)
+ .ConfigureWarnings(e => e.Throw(RelationalEventId.ModelSnapshotNotFound))).Options);
+
+ context.Database.EnsureDeleted();
+ GiveMeSomeTime(context);
+
+ Assert.Equal(
+ CoreStrings.WarningAsErrorTemplate(
+ RelationalEventId.ModelSnapshotNotFound.ToString(),
+ RelationalResources.LogNoModelSnapshotFound(new TestLogger())
+ .GenerateMessage(typeof(MigrationsContext).Assembly.GetName().Name),
+ "RelationalEventId.ModelSnapshotNotFound"),
+ (Assert.Throws(context.Database.Migrate)).Message);
+ }
+
+ [ConditionalFact]
+ public async Task Throws_when_no_snapshot_async()
+ {
+ using var context = new MigrationsContext(
+ Fixture.TestStore.AddProviderOptions(
+ new DbContextOptionsBuilder().EnableServiceProviderCaching(false)
+ .ConfigureWarnings(e => e.Throw(RelationalEventId.ModelSnapshotNotFound))).Options);
+
+ await context.Database.EnsureDeletedAsync();
+ await GiveMeSomeTimeAsync(context);
+
+ Assert.Equal(
+ CoreStrings.WarningAsErrorTemplate(
+ RelationalEventId.ModelSnapshotNotFound.ToString(),
+ RelationalResources.LogNoModelSnapshotFound(new TestLogger())
+ .GenerateMessage(typeof(MigrationsContext).Assembly.GetName().Name),
+ "RelationalEventId.ModelSnapshotNotFound"),
+ (await Assert.ThrowsAsync(() => context.Database.MigrateAsync())).Message);
+ }
+
+ [ConditionalFact]
+ public void Throws_for_nondeterministic_HasData()
+ {
+ using var context = new BloggingContext(
+ Fixture.TestStore.AddProviderOptions(
+ new DbContextOptionsBuilder().EnableServiceProviderCaching(false)).Options,
+ randomData: true);
+
+ context.Database.EnsureDeleted();
+ GiveMeSomeTime(context);
+
+ Assert.Equal(
+ CoreStrings.WarningAsErrorTemplate(
+ RelationalEventId.PendingModelChangesWarning.ToString(),
+ RelationalResources.LogNonDeterministicModel(new TestLogger())
+ .GenerateMessage(nameof(BloggingContext)),
+ "RelationalEventId.PendingModelChangesWarning"),
+ (Assert.Throws(context.Database.Migrate)).Message);
+ }
+
+ [ConditionalFact]
+ public async Task Throws_for_nondeterministic_HasData_async()
+ {
+ using var context = new BloggingContext(
+ Fixture.TestStore.AddProviderOptions(
+ new DbContextOptionsBuilder().EnableServiceProviderCaching(false)).Options,
+ randomData: true);
+
+ await context.Database.EnsureDeletedAsync();
+ await GiveMeSomeTimeAsync(context);
+
+ Assert.Equal(
+ CoreStrings.WarningAsErrorTemplate(
+ RelationalEventId.PendingModelChangesWarning.ToString(),
+ RelationalResources.LogNonDeterministicModel(new TestLogger())
+ .GenerateMessage(nameof(BloggingContext)),
+ "RelationalEventId.PendingModelChangesWarning"),
+ (await Assert.ThrowsAsync(() => context.Database.MigrateAsync())).Message);
+ }
+
[ConditionalFact]
public void Throws_for_pending_model_changes()
{
using var context = new BloggingContext(
Fixture.TestStore.AddProviderOptions(
- new DbContextOptionsBuilder().EnableServiceProviderCaching(false)).Options);
+ new DbContextOptionsBuilder().EnableServiceProviderCaching(false)).Options,
+ randomData: false);
+
+ context.Database.EnsureDeleted();
+ GiveMeSomeTime(context);
Assert.Equal(
CoreStrings.WarningAsErrorTemplate(
@@ -671,7 +796,11 @@ public async Task Throws_for_pending_model_changes_async()
{
using var context = new BloggingContext(
Fixture.TestStore.AddProviderOptions(
- new DbContextOptionsBuilder().EnableServiceProviderCaching(false)).Options);
+ new DbContextOptionsBuilder().EnableServiceProviderCaching(false)).Options,
+ randomData: false);
+
+ await context.Database.EnsureDeletedAsync();
+ await GiveMeSomeTimeAsync(context);
Assert.Equal(
CoreStrings.WarningAsErrorTemplate(
@@ -925,7 +1054,7 @@ SELECT @result
ignoreLineEndingDifferences: true);
}
- private class BloggingContext(DbContextOptions options) : DbContext(options)
+ private class BloggingContext(DbContextOptions options, bool? randomData = null) : DbContext(options)
{
// ReSharper disable once UnusedMember.Local
public DbSet Blogs { get; set; }
@@ -939,6 +1068,46 @@ public class Blog
public string Name { get; set; }
// ReSharper restore UnusedMember.Local
}
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ if (randomData != null)
+ {
+ modelBuilder.Entity().HasData(
+ new Blog { Id = randomData.Value ? (int)new Random().NextInt64(int.MaxValue) : 1, Name = "HalfADonkey" });
+ }
+ }
+ }
+
+ [DbContext(typeof(BloggingContext))]
+ partial class BloggingContextSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("Microsoft.EntityFrameworkCore.Migrations.MigrationsInfrastructureSqlServerTest+BloggingContext+Blog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Name")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Blogs");
+ });
+#pragma warning restore 612, 618
+ }
}
[DbContext(typeof(BloggingContext))]