Skip to content

Commit

Permalink
Remove LazyRef
Browse files Browse the repository at this point in the history
Fixes #15282
  • Loading branch information
ajcvickers committed Apr 21, 2019
1 parent a69d84b commit dc81f51
Show file tree
Hide file tree
Showing 11 changed files with 223 additions and 328 deletions.
127 changes: 75 additions & 52 deletions src/EFCore.Design/Design/OperationExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,19 @@ namespace Microsoft.EntityFrameworkCore.Design
/// </summary>
public class OperationExecutor : MarshalByRefObject
{
private readonly LazyRef<DbContextOperations> _contextOperations;
private readonly LazyRef<DatabaseOperations> _databaseOperations;
private readonly LazyRef<MigrationsOperations> _migrationsOperations;
private readonly string _projectDir;
private readonly string _targetName;
private readonly string _startupTargetName;
private readonly string _rootNamespace;
private readonly string _language;
private readonly string[] _designArgs;
private readonly OperationReporter _reporter;

private DbContextOperations _contextOperations;
private DatabaseOperations _databaseOperations;
private MigrationsOperations _migrationsOperations;
private Assembly _assembly;
private Assembly _startupAssembly;

/// <summary>
/// <para>Initializes a new instance of the <see cref="OperationExecutor" /> class.</para>
Expand All @@ -46,67 +55,82 @@ public OperationExecutor([NotNull] object reportHandler, [NotNull] IDictionary a
Check.NotNull(args, nameof(args));

var unwrappedReportHandler = ForwardingProxy.Unwrap<IOperationReportHandler>(reportHandler);
var reporter = new OperationReporter(unwrappedReportHandler);

var targetName = (string)args["targetName"];
var startupTargetName = (string)args["startupTargetName"];
_reporter = new OperationReporter(unwrappedReportHandler);
_targetName = (string)args["targetName"];
_startupTargetName = (string)args["startupTargetName"];
_projectDir = (string)args["projectDir"];
var rootNamespace = (string)args["rootNamespace"];
var language = (string)args["language"];
var toolsVersion = (string)args["toolsVersion"];
_rootNamespace = (string)args["rootNamespace"];
_language = (string)args["language"];

// TODO: Flow in from tools (issue #8332)
var designArgs = Array.Empty<string>();
_designArgs = Array.Empty<string>();

var toolsVersion = (string)args["toolsVersion"];
var runtimeVersion = ProductInfo.GetVersion();
if (toolsVersion != null
&& new SemanticVersionComparer().Compare(toolsVersion, runtimeVersion) < 0)
{
reporter.WriteWarning(DesignStrings.VersionMismatch(toolsVersion, runtimeVersion));
_reporter.WriteWarning(DesignStrings.VersionMismatch(toolsVersion, runtimeVersion));
}
}

// NOTE: LazyRef is used so any exceptions get passed to the resultHandler
var startupAssembly = new LazyRef<Assembly>(
() => Assembly.Load(new AssemblyName(startupTargetName)));
var assembly = new LazyRef<Assembly>(
() =>
private Assembly Assembly
{
get
{
Assembly Create()
{
try
{
return Assembly.Load(new AssemblyName(targetName));
return Assembly.Load(new AssemblyName(_targetName));
}
catch (Exception ex)
{
throw new OperationException(
DesignStrings.UnreferencedAssembly(targetName, startupTargetName),
DesignStrings.UnreferencedAssembly(_targetName, _startupTargetName),
ex);
}
});
_contextOperations = new LazyRef<DbContextOperations>(
() => new DbContextOperations(
reporter,
assembly.Value,
startupAssembly.Value,
designArgs));
_databaseOperations = new LazyRef<DatabaseOperations>(
() => new DatabaseOperations(
reporter,
assembly.Value,
startupAssembly.Value,
}

return _assembly ??= Create();
}
}

private Assembly StartupAssembly
=> _startupAssembly
??= Assembly.Load(new AssemblyName(_startupTargetName));

private MigrationsOperations MigrationsOperations
=> _migrationsOperations
??= new MigrationsOperations(
_reporter,
Assembly,
StartupAssembly,
_projectDir,
rootNamespace,
language,
designArgs));
_migrationsOperations = new LazyRef<MigrationsOperations>(
() => new MigrationsOperations(
reporter,
assembly.Value,
startupAssembly.Value,
_rootNamespace,
_language,
_designArgs);


private DbContextOperations ContextOperations
=> _contextOperations
??= new DbContextOperations(
_reporter,
Assembly,
StartupAssembly,
_designArgs);

private DatabaseOperations DatabaseOperations
=> _databaseOperations
??= new DatabaseOperations(
_reporter,
Assembly,
StartupAssembly,
_projectDir,
rootNamespace,
language,
designArgs));
}
_rootNamespace,
_language,
_designArgs);

/// <summary>
/// Represents an operation to add a new migration.
Expand Down Expand Up @@ -150,7 +174,7 @@ private IDictionary AddMigrationImpl(
{
Check.NotEmpty(name, nameof(name));

var files = _migrationsOperations.Value.AddMigration(
var files = MigrationsOperations.AddMigration(
name,
outputDir,
contextType);
Expand Down Expand Up @@ -189,7 +213,7 @@ public GetContextInfo([NotNull] OperationExecutor executor, [NotNull] object res

private IDictionary GetContextInfoImpl([CanBeNull] string contextType)
{
var info = _contextOperations.Value.GetContextInfo(contextType);
var info = ContextOperations.GetContextInfo(contextType);
return new Hashtable
{
["ProviderName"] = info.ProviderName,
Expand Down Expand Up @@ -230,7 +254,7 @@ public UpdateDatabase([NotNull] OperationExecutor executor, [NotNull] object res
}

private void UpdateDatabaseImpl([CanBeNull] string targetMigration, [CanBeNull] string contextType) =>
_migrationsOperations.Value.UpdateDatabase(targetMigration, contextType);
MigrationsOperations.UpdateDatabase(targetMigration, contextType);

/// <summary>
/// Represents an operation to generate a SQL script from migrations.
Expand Down Expand Up @@ -271,7 +295,7 @@ private string ScriptMigrationImpl(
[CanBeNull] string toMigration,
bool idempotent,
[CanBeNull] string contextType)
=> _migrationsOperations.Value.ScriptMigration(
=> MigrationsOperations.ScriptMigration(
fromMigration,
toMigration,
idempotent,
Expand Down Expand Up @@ -309,8 +333,7 @@ public RemoveMigration(

private IDictionary RemoveMigrationImpl([CanBeNull] string contextType, bool force)
{
var files = _migrationsOperations.Value
.RemoveMigration(contextType, force);
var files = MigrationsOperations.RemoveMigration(contextType, force);

return new Hashtable
{
Expand Down Expand Up @@ -344,7 +367,7 @@ public GetContextTypes([NotNull] OperationExecutor executor, [NotNull] object re

private IEnumerable<IDictionary> GetContextTypesImpl()
{
var contextTypes = _contextOperations.Value.GetContextTypes().ToList();
var contextTypes = ContextOperations.GetContextTypes().ToList();
var nameGroups = contextTypes.GroupBy(t => t.Name).ToList();
var fullNameGroups = contextTypes.GroupBy(t => t.FullName).ToList();

Expand Down Expand Up @@ -389,7 +412,7 @@ public GetMigrations([NotNull] OperationExecutor executor, [NotNull] object resu

private IEnumerable<IDictionary> GetMigrationsImpl([CanBeNull] string contextType)
{
var migrations = _migrationsOperations.Value.GetMigrations(contextType).ToList();
var migrations = MigrationsOperations.GetMigrations(contextType).ToList();
var nameGroups = migrations.GroupBy(m => m.Name).ToList();

return migrations.Select(
Expand Down Expand Up @@ -466,7 +489,7 @@ private IDictionary ScaffoldContextImpl(
Check.NotNull(schemaFilters, nameof(schemaFilters));
Check.NotNull(tableFilters, nameof(tableFilters));

var files = _databaseOperations.Value.ScaffoldContext(
var files = DatabaseOperations.ScaffoldContext(
provider, connectionString, outputDir, outputDbContextDir, dbContextClassName,
schemaFilters, tableFilters, useDataAnnotations, overwriteFiles, useDatabaseNames);

Expand Down Expand Up @@ -506,7 +529,7 @@ public DropDatabase(
}

private void DropDatabaseImpl(string contextType)
=> _contextOperations.Value.DropDatabase(contextType);
=> ContextOperations.DropDatabase(contextType);

/// <summary>
/// Represents an operation.
Expand Down
20 changes: 6 additions & 14 deletions src/EFCore.Relational/Infrastructure/ModelSnapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

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

Expand All @@ -13,27 +12,20 @@ namespace Microsoft.EntityFrameworkCore.Infrastructure
/// </summary>
public abstract class ModelSnapshot
{
private readonly LazyRef<IModel> _model;
private IModel _model;

/// <summary>
/// Constructs a new snapshot instance.
/// </summary>
protected ModelSnapshot()
private IMutableModel CreateModel()
{
_model = new LazyRef<IModel>(
() =>
{
var modelBuilder = new ModelBuilder(new ConventionSet());
BuildModel(modelBuilder);
var modelBuilder = new ModelBuilder(new ConventionSet());
BuildModel(modelBuilder);

return modelBuilder.Model;
});
return modelBuilder.Model;
}

/// <summary>
/// The snapshot model.
/// </summary>
public virtual IModel Model => _model.Value;
public virtual IModel Model => _model ??= CreateModel();

/// <summary>
/// Called lazily by <see cref="Model" /> to build the model snapshot
Expand Down
66 changes: 39 additions & 27 deletions src/EFCore.Relational/Migrations/HistoryRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Storage;
Expand Down Expand Up @@ -41,9 +40,9 @@ public abstract class HistoryRepository : IHistoryRepository
/// </summary>
public const string DefaultTableName = "__EFMigrationsHistory";

private readonly LazyRef<IModel> _model;
private readonly LazyRef<string> _migrationIdColumnName;
private readonly LazyRef<string> _productVersionColumnName;
private IModel _model;
private string _migrationIdColumnName;
private string _productVersionColumnName;

/// <summary>
/// Initializes a new instance of this class.
Expand All @@ -58,25 +57,6 @@ protected HistoryRepository([NotNull] HistoryRepositoryDependencies dependencies
var relationalOptions = RelationalOptionsExtension.Extract(dependencies.Options);
TableName = relationalOptions?.MigrationsHistoryTableName ?? DefaultTableName;
TableSchema = relationalOptions?.MigrationsHistoryTableSchema;
_model = new LazyRef<IModel>(
() =>
{
var modelBuilder = new ModelBuilder(Dependencies.ConventionSetBuilder.CreateConventionSet());
modelBuilder.Entity<HistoryRow>(
x =>
{
ConfigureTable(x);
x.ToTable(TableName, TableSchema);
});
return modelBuilder.Model;
});
var entityType = new LazyRef<IEntityType>(() => _model.Value.FindEntityType(typeof(HistoryRow)));
_migrationIdColumnName = new LazyRef<string>(
() => entityType.Value.FindProperty(nameof(HistoryRow.MigrationId)).Relational().ColumnName);
_productVersionColumnName = new LazyRef<string>(
() => entityType.Value.FindProperty(nameof(HistoryRow.ProductVersion)).Relational().ColumnName);
}

/// <summary>
Expand All @@ -102,12 +82,42 @@ protected HistoryRepository([NotNull] HistoryRepositoryDependencies dependencies
/// <summary>
/// The name of the column that holds the Migration identifier.
/// </summary>
protected virtual string MigrationIdColumnName => _migrationIdColumnName.Value;
protected virtual string MigrationIdColumnName
=> _migrationIdColumnName
??= EnsureModel()
.FindEntityType(typeof(HistoryRow))
.FindProperty(nameof(HistoryRow.MigrationId))
.Relational()
.ColumnName;

private IModel EnsureModel()
{
if (_model == null)
{
var modelBuilder = new ModelBuilder(Dependencies.ConventionSetBuilder.CreateConventionSet());

modelBuilder.Entity<HistoryRow>(
x =>
{
ConfigureTable(x);
x.ToTable(TableName, TableSchema);
});

_model = modelBuilder.Model;
}

return _model;
}

/// <summary>
/// The name of the column that contains the Entity Framework product version.
/// </summary>
protected virtual string ProductVersionColumnName => _productVersionColumnName.Value;
protected virtual string ProductVersionColumnName
=> _productVersionColumnName ??= EnsureModel()
.FindEntityType(typeof(HistoryRow))
.FindProperty(nameof(HistoryRow.ProductVersion))
.Relational()
.ColumnName;

/// <summary>
/// Overridden by database providers to generate SQL that tests for existence of the history table.
Expand Down Expand Up @@ -156,8 +166,10 @@ await Dependencies.RawSqlCommandBuilder.Build(ExistsSql).ExecuteScalarAsync(
/// <returns> The SQL script. </returns>
public virtual string GetCreateScript()
{
var operations = Dependencies.ModelDiffer.GetDifferences(null, _model.Value);
var commandList = Dependencies.MigrationsSqlGenerator.Generate(operations, _model.Value);
var model = EnsureModel();

var operations = Dependencies.ModelDiffer.GetDifferences(null, model);
var commandList = Dependencies.MigrationsSqlGenerator.Generate(operations, model);

return string.Concat(commandList.Select(c => c.CommandText));
}
Expand Down
Loading

0 comments on commit dc81f51

Please sign in to comment.