Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use clean StateManager for seeding #16368

Merged
merged 1 commit into from
Jul 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/EFCore.Cosmos/Storage/Internal/CosmosDatabaseCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public bool EnsureCreated()

if (created)
{
var updateAdapter = _updateAdapterFactory.Create();
var updateAdapter = _updateAdapterFactory.CreateStandalone();
foreach (var entityType in _model.GetEntityTypes())
{
foreach (var targetSeed in entityType.GetSeedData())
Expand Down Expand Up @@ -70,7 +70,7 @@ public async Task<bool> EnsureCreatedAsync(CancellationToken cancellationToken =

if (created)
{
var updateAdapter = _updateAdapterFactory.Create();
var updateAdapter = _updateAdapterFactory.CreateStandalone();
foreach (var entityType in _model.GetEntityTypes())
{
foreach (var targetSeed in entityType.GetSeedData())
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore.InMemory/Storage/Internal/InMemoryStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public virtual bool EnsureCreated(
// ReSharper disable once AssignmentIsFullyDiscarded
_tables = CreateTables();

var updateAdapter = updateAdapterFactory.Create();
var updateAdapter = updateAdapterFactory.CreateStandalone();
var entries = new List<IUpdateEntry>();
foreach (var entityType in updateAdapter.Model.GetEntityTypes())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1598,7 +1598,7 @@ protected virtual void TrackData(
return;
}

_targetUpdateAdapter = UpdateAdapterFactory.Create(target);
_targetUpdateAdapter = UpdateAdapterFactory.CreateStandalone(target);

foreach (var targetEntityType in target.GetEntityTypes())
{
Expand All @@ -1616,7 +1616,7 @@ protected virtual void TrackData(
return;
}

_sourceUpdateAdapter = UpdateAdapterFactory.Create(source);
_sourceUpdateAdapter = UpdateAdapterFactory.CreateStandalone(source);

foreach (var sourceEntityType in source.GetEntityTypes())
{
Expand Down
8 changes: 8 additions & 0 deletions src/EFCore/ChangeTracking/Internal/IStateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal
/// </summary>
public interface IStateManager : IResettableService
{
/// <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>
StateManagerDependencies Dependencies { get; }

/// <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
Expand Down
10 changes: 10 additions & 0 deletions src/EFCore/ChangeTracking/Internal/StateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ private readonly EntityReferenceMap _entityReferenceMap
/// </summary>
public StateManager([NotNull] StateManagerDependencies dependencies)
{
Dependencies = dependencies;

_internalEntityEntryFactory = dependencies.InternalEntityEntryFactory;
_internalEntityEntrySubscriber = dependencies.InternalEntityEntrySubscriber;
InternalEntityEntryNotifier = dependencies.InternalEntityEntryNotifier;
Expand All @@ -83,6 +85,14 @@ public StateManager([NotNull] StateManagerDependencies dependencies)
_changeTrackingLogger = dependencies.ChangeTrackingLogger;
}

/// <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 StateManagerDependencies Dependencies { get; }

/// <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
Expand Down
21 changes: 18 additions & 3 deletions src/EFCore/Update/IUpdateAdapterFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Metadata;

namespace Microsoft.EntityFrameworkCore.Update
{
/// <summary>
/// <para>
/// Factory for creating <see cref="IUpdateAdapter"/> instances.
/// Factory for creating <see cref="IUpdateAdapter" /> instances.
/// </para>
/// <para>
/// This interface is typically used by database providers (and other extensions). It is generally
Expand All @@ -18,10 +19,24 @@ namespace Microsoft.EntityFrameworkCore.Update
public interface IUpdateAdapterFactory
{
/// <summary>
/// Creates a tracker for the given model.
/// Creates a tracker for the model currently in use.
/// </summary>
/// <returns> The new tracker. </returns>
IUpdateAdapter Create();

/// <summary>
/// <para>
/// Creates a standalone tracker that works with its own <see cref="IStateManager"/> and hence will not
/// impact tracking on the state manager currently in use.
/// </para>
/// <para>
/// The <see cref="IUpdateAdapter.Entries" /> from this update adapter should be used explicitly
/// once they have been setup. They will not be visible to other parts of the stack,
/// including <see cref="DbContext.SaveChanges()" />.
/// </para>
/// </summary>
/// <param name="model"> The model for which a tracker is needed, or null to use the current model. </param>
/// <returns> The new tracker. </returns>
IUpdateAdapter Create([CanBeNull] IModel model = null);
IUpdateAdapter CreateStandalone([CanBeNull] IModel model = null);
}
}
7 changes: 3 additions & 4 deletions src/EFCore/Update/Internal/UpdateAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;

namespace Microsoft.EntityFrameworkCore.Update.Internal
Expand All @@ -25,12 +26,10 @@ public class UpdateAdapter : IUpdateAdapter
/// 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 UpdateAdapter(
[NotNull] IStateManager stateManager,
[NotNull] IChangeDetector changeDetector)
public UpdateAdapter([NotNull] IStateManager stateManager)
{
_stateManager = stateManager;
_changeDetector = changeDetector;
_changeDetector = _stateManager.Context.GetDependencies().ChangeDetector;
}

/// <summary>
Expand Down
35 changes: 22 additions & 13 deletions src/EFCore/Update/Internal/UpdateAdapterFactory.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// 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 JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.EntityFrameworkCore.Update.Internal
{
Expand All @@ -17,18 +17,17 @@ namespace Microsoft.EntityFrameworkCore.Update.Internal
/// </summary>
public class UpdateAdapterFactory : IUpdateAdapterFactory
{
private readonly IServiceProvider _serviceProvider;
private readonly ICurrentDbContext _currentDbContext;

/// <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 UpdateAdapterFactory(
[NotNull] IServiceProvider serviceProvider)
public UpdateAdapterFactory([NotNull] ICurrentDbContext currentDbContext)
{
_serviceProvider = serviceProvider;
_currentDbContext = currentDbContext;
}

/// <summary>
Expand All @@ -37,12 +36,22 @@ public UpdateAdapterFactory(
/// 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 IUpdateAdapter Create(IModel model = null)
=> new UpdateAdapter(
model == null
? _serviceProvider.GetService<IStateManager>()
: new StateManager(
_serviceProvider.GetService<StateManagerDependencies>().With(model)),
_serviceProvider.GetService<IChangeDetector>());
public virtual IUpdateAdapter Create()
=> new UpdateAdapter(_currentDbContext.Context.GetDependencies().StateManager);

/// <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 IUpdateAdapter CreateStandalone(IModel model = null)
{
var stateManager = _currentDbContext.Context.GetDependencies().StateManager;

return model == null
? new UpdateAdapter(new StateManager(stateManager.Dependencies))
: new UpdateAdapter(new StateManager(stateManager.Dependencies.With(model)));
}
}
}
21 changes: 21 additions & 0 deletions test/EFCore.InMemory.FunctionalTests/SeedingInMemoryTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// 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.
namespace Microsoft.EntityFrameworkCore
{
public class SeedingInMemoryTest : SeedingTestBase
{
protected override SeedingContext CreateContextWithEmptyDatabase(string testId)
=> new SeedingInMemoryContext(testId);

protected class SeedingInMemoryContext : SeedingContext
{
public SeedingInMemoryContext(string testId)
: base(testId)
{
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseInMemoryDatabase($"Seeds{TestId}");
}
}
}
Loading