Skip to content

Commit

Permalink
Move seeding to options
Browse files Browse the repository at this point in the history
  • Loading branch information
AndriySvyryd committed Aug 10, 2024
1 parent 1b05ae8 commit f8ca271
Show file tree
Hide file tree
Showing 34 changed files with 605 additions and 367 deletions.
50 changes: 42 additions & 8 deletions src/EFCore.Cosmos/Storage/Internal/CosmosDatabaseCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public class CosmosDatabaseCreator : IDatabaseCreator
private readonly IDesignTimeModel _designTimeModel;
private readonly IUpdateAdapterFactory _updateAdapterFactory;
private readonly IDatabase _database;
private readonly ICurrentDbContext _currentContext;
private readonly IDbContextOptions _contextOptions;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand All @@ -28,12 +30,16 @@ public CosmosDatabaseCreator(
ICosmosClientWrapper cosmosClient,
IDesignTimeModel designTimeModel,
IUpdateAdapterFactory updateAdapterFactory,
IDatabase database)
IDatabase database,
ICurrentDbContext currentContext,
IDbContextOptions contextOptions)
{
_cosmosClient = cosmosClient;
_designTimeModel = designTimeModel;
_updateAdapterFactory = updateAdapterFactory;
_database = database;
_currentContext = currentContext;
_contextOptions = contextOptions;
}

/// <summary>
Expand All @@ -54,7 +60,21 @@ public virtual bool EnsureCreated()

if (created)
{
Seed();
InsertData();
}

var coreOptionsExtension =
_contextOptions.FindExtension<CoreOptionsExtension>()
?? new CoreOptionsExtension();

var seed = coreOptionsExtension.Seeder;
if (seed != null)
{
seed(_currentContext.Context, created);
}
else if (coreOptionsExtension.AsyncSeeder != null)
{
throw new InvalidOperationException(CoreStrings.MissingSeeder);
}

return created;
Expand All @@ -80,7 +100,21 @@ public virtual async Task<bool> EnsureCreatedAsync(CancellationToken cancellatio

if (created)
{
await SeedAsync(cancellationToken).ConfigureAwait(false);
await InsertDataAsync(cancellationToken).ConfigureAwait(false);
}

var coreOptionsExtension =
_contextOptions.FindExtension<CoreOptionsExtension>()
?? new CoreOptionsExtension();

var seedAsync = coreOptionsExtension.AsyncSeeder;
if (seedAsync != null)
{
await seedAsync(_currentContext.Context, created, cancellationToken).ConfigureAwait(false);
}
else if (coreOptionsExtension.Seeder != null)
{
throw new InvalidOperationException(CoreStrings.MissingSeeder);
}

return created;
Expand Down Expand Up @@ -139,9 +173,9 @@ private static IEnumerable<ContainerProperties> GetContainersToCreate(IModel mod
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual void Seed()
public virtual void InsertData()
{
var updateAdapter = AddSeedData();
var updateAdapter = AddModelData();

_database.SaveChanges(updateAdapter.GetEntriesToSave());
}
Expand All @@ -152,14 +186,14 @@ public virtual void Seed()
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual Task SeedAsync(CancellationToken cancellationToken = default)
public virtual Task InsertDataAsync(CancellationToken cancellationToken = default)
{
var updateAdapter = AddSeedData();
var updateAdapter = AddModelData();

return _database.SaveChangesAsync(updateAdapter.GetEntriesToSave(), cancellationToken);
}

private IUpdateAdapter AddSeedData()
private IUpdateAdapter AddModelData()
{
var updateAdapter = _updateAdapterFactory.CreateStandalone();
foreach (var entityType in _designTimeModel.Model.GetEntityTypes())
Expand Down
2 changes: 0 additions & 2 deletions src/EFCore.Design/Design/Internal/DbContextOperations.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
using System.Text;
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.MSBuild;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.EntityFrameworkCore.Infrastructure.Internal;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
Expand Down
3 changes: 1 addition & 2 deletions src/EFCore.Design/Design/Internal/MigrationsOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,7 @@ public virtual void UpdateDatabase(
EnsureServices(services);

var migrator = services.GetRequiredService<IMigrator>();

migrator.Migrate(targetMigration: targetMigration);
migrator.Migrate(targetMigration);
}

_reporter.WriteInformation(DesignStrings.Done);
Expand Down
51 changes: 47 additions & 4 deletions src/EFCore.InMemory/Storage/Internal/InMemoryDatabaseCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,23 @@ namespace Microsoft.EntityFrameworkCore.InMemory.Storage.Internal;
public class InMemoryDatabaseCreator : IDatabaseCreator
{
private readonly IDatabase _database;
private readonly ICurrentDbContext _currentContext;
private readonly IDbContextOptions _contextOptions;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public InMemoryDatabaseCreator(IDatabase database)
public InMemoryDatabaseCreator(
IDatabase database,
ICurrentDbContext currentContext,
IDbContextOptions contextOptions)
{
_database = database;
_currentContext = currentContext;
_contextOptions = contextOptions;
}

/// <summary>
Expand Down Expand Up @@ -58,16 +65,52 @@ public virtual Task<bool> EnsureDeletedAsync(CancellationToken cancellationToken
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual bool EnsureCreated()
=> Database.EnsureDatabaseCreated();
{
var created = Database.EnsureDatabaseCreated();

var coreOptionsExtension =
_contextOptions.FindExtension<CoreOptionsExtension>()
?? new CoreOptionsExtension();

var seed = coreOptionsExtension.Seeder;
if (seed != null)
{
seed(_currentContext.Context, created);
}
else if (coreOptionsExtension.AsyncSeeder != null)
{
throw new InvalidOperationException(CoreStrings.MissingSeeder);
}

return created;
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual Task<bool> EnsureCreatedAsync(CancellationToken cancellationToken = default)
=> Task.FromResult(Database.EnsureDatabaseCreated());
public virtual async Task<bool> EnsureCreatedAsync(CancellationToken cancellationToken = default)
{
var created = Database.EnsureDatabaseCreated();

var coreOptionsExtension =
_contextOptions.FindExtension<CoreOptionsExtension>()
?? new CoreOptionsExtension();

var seedAsync = coreOptionsExtension.AsyncSeeder;
if (seedAsync != null)
{
await seedAsync(_currentContext.Context, created, cancellationToken).ConfigureAwait(false);
}
else if (coreOptionsExtension.Seeder != null)
{
throw new InvalidOperationException(CoreStrings.MissingSeeder);
}

return created;
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,6 @@ public static void Migrate(this DatabaseFacade databaseFacade)
/// <param name="targetMigration">
/// The target migration to migrate the database to, or <see langword="null" /> to migrate to the latest.
/// </param>
/// <param name="seed">
/// The optional seed method to run after migrating the database. It will be invoked even if no migrations were applied.
/// </param>
/// <remarks>
/// <para>
/// Note that this API is mutually exclusive with <see cref="DatabaseFacade.EnsureCreated" />. EnsureCreated does not use migrations
Expand All @@ -141,9 +138,8 @@ public static void Migrate(this DatabaseFacade databaseFacade)
+ " Use a migration bundle or an alternate way of executing migration operations.")]
public static void Migrate(
this DatabaseFacade databaseFacade,
Action<DbContext, IMigratorData>? seed,
string? targetMigration = null)
=> databaseFacade.GetRelationalService<IMigrator>().Migrate(seed, targetMigration);
string? targetMigration)
=> databaseFacade.GetRelationalService<IMigrator>().Migrate(targetMigration);

/// <summary>
/// Asynchronously applies any pending migrations for the context to the database. Will create the database
Expand Down Expand Up @@ -179,9 +175,6 @@ public static Task MigrateAsync(
/// <param name="targetMigration">
/// The target migration to migrate the database to, or <see langword="null" /> to migrate to the latest.
/// </param>
/// <param name="seed">
/// The optional seed method to run after migrating the database. It will be invoked even if no migrations were applied.
/// </param>
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
/// <remarks>
/// <para>
Expand All @@ -200,10 +193,9 @@ public static Task MigrateAsync(
+ " Use a migration bundle or an alternate way of executing migration operations.")]
public static Task MigrateAsync(
this DatabaseFacade databaseFacade,
Func<DbContext, IMigratorData, CancellationToken, Task>? seed,
string? targetMigration = null,
string? targetMigration,
CancellationToken cancellationToken = default)
=> databaseFacade.GetRelationalService<IMigrator>().MigrateAsync(seed, targetMigration, cancellationToken);
=> databaseFacade.GetRelationalService<IMigrator>().MigrateAsync(targetMigration, cancellationToken);

/// <summary>
/// Executes the given SQL against the database and returns the number of rows affected.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ public static readonly IDictionary<Type, ServiceCharacteristics> RelationalServi
typeof(IAggregateMethodCallTranslatorPlugin),
new ServiceCharacteristics(ServiceLifetime.Scoped, multipleRegistrations: true)
},
{ typeof(IMemberTranslatorPlugin), new ServiceCharacteristics(ServiceLifetime.Scoped, multipleRegistrations: true) },
{ typeof(IMigratorPlugin), new ServiceCharacteristics(ServiceLifetime.Singleton, multipleRegistrations: true) }
{ typeof(IMemberTranslatorPlugin), new ServiceCharacteristics(ServiceLifetime.Scoped, multipleRegistrations: true) }
};

/// <summary>
Expand Down
9 changes: 1 addition & 8 deletions src/EFCore.Relational/Migrations/IMigrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ public interface IMigrator
/// Migrates the database to either a specified target migration or up to the latest
/// migration that exists in the <see cref="IMigrationsAssembly" />.
/// </summary>
/// <param name="seed">
/// The optional seed method to run after migrating the database. It will be invoked even if no migrations were applied.
/// </param>
/// <param name="targetMigration">
/// The target migration to migrate the database to, or <see langword="null" /> to migrate to the latest.
/// </param>
Expand All @@ -37,15 +34,12 @@ public interface IMigrator
/// </remarks>
[RequiresUnreferencedCode("Migration generation currently isn't compatible with trimming")]
[RequiresDynamicCode("Migrations operations are not supported with NativeAOT")]
void Migrate(Action<DbContext, IMigratorData>? seed = null, string? targetMigration = null);
void Migrate(string? targetMigration = null);

/// <summary>
/// Migrates the database to either a specified target migration or up to the latest
/// migration that exists in the <see cref="IMigrationsAssembly" />.
/// </summary>
/// <param name="seed">
/// The optional seed method to run after migrating the database. It will be invoked even if no migrations were applied.
/// </param>
/// <param name="targetMigration">
/// The target migration to migrate the database to, or <see langword="null" /> to migrate to the latest.
/// </param>
Expand All @@ -58,7 +52,6 @@ public interface IMigrator
[RequiresUnreferencedCode("Migration generation currently isn't compatible with trimming")]
[RequiresDynamicCode("Migrations operations are not supported with NativeAOT")]
Task MigrateAsync(
Func<DbContext, IMigratorData, CancellationToken, Task>? seed = null,
string? targetMigration = null,
CancellationToken cancellationToken = default);

Expand Down
29 changes: 0 additions & 29 deletions src/EFCore.Relational/Migrations/IMigratorData.cs

This file was deleted.

Loading

0 comments on commit f8ca271

Please sign in to comment.