Permalink
Browse files

History table configuration part 1

- Move history table management into main pipeline.
- Adds history model metadata into user model metadata.
- Introduces IsSystem to MigrationOperation to differentiate history ops from users ops.
- Use IsSystem instead of anonymous arg in SQL gen to make history a system table.
- Added FTs for upgrade scenarios.
  • Loading branch information...
1 parent ba9a543 commit 9baca562ee3a747a41870f45e749e4436b6aca26 @anpete anpete committed Jul 20, 2012
Showing with 750 additions and 503 deletions.
  1. +1 −0 src/EntityFramework/EntityFramework.csproj
  2. +2 −1 src/EntityFramework/Internal/DatabaseCreator.cs
  3. +95 −70 src/EntityFramework/Migrations/DbMigrator.cs
  4. +15 −0 src/EntityFramework/Migrations/Edm/EdmXNames.cs
  5. +51 −78 src/EntityFramework/Migrations/History/HistoryRepository.cs
  6. +87 −72 src/EntityFramework/Migrations/Infrastructure/EdmModelDiffer.cs
  7. +3 −9 src/EntityFramework/Migrations/Infrastructure/MigratorBase.cs
  8. +2 −2 src/EntityFramework/Migrations/Infrastructure/MigratorLoggingDecorator.cs
  9. +0 −13 src/EntityFramework/Migrations/Infrastructure/MigratorScriptingDecorator.cs
  10. +2 −0 src/EntityFramework/Migrations/Model/MigrationOperation.cs
  11. +1 −5 src/EntityFramework/Migrations/Sql/SqlServerMigrationSqlGenerator.cs
  12. +1 −8 src/EntityFramework/Utilities/DbContextExtensions.cs
  13. +18 −0 src/EntityFramework/Utilities/DbModelExtensions.cs
  14. +7 −0 src/EntityFramework/Utilities/XDocumentExtensions.cs
  15. +1 −1 test/EntityFramework/FunctionalTests/FunctionalTests.csproj
  16. +1 −3 test/EntityFramework/FunctionalTests/Migrations/DashScriptScenarios.cs
  17. +1 −73 test/EntityFramework/FunctionalTests/Migrations/SchemaScenarios.cs
  18. +33 −0 test/EntityFramework/FunctionalTests/Migrations/TestHelpers/DbTestCase.cs
  19. +145 −0 test/EntityFramework/FunctionalTests/Migrations/UpgradeScenarios.cs
  20. +0 −25 test/EntityFramework/FunctionalTests/TestHelpers/DbModelExtensions.cs
  21. +3 −2 test/EntityFramework/UnitTests/Internal/DatabaseCreatorTests.cs
  22. +16 −10 test/EntityFramework/UnitTests/Migrations/DbMigratorTests.cs
  23. +2 −1 test/EntityFramework/UnitTests/Migrations/Edm/ModelCompressorTests.cs
  24. +91 −68 test/EntityFramework/UnitTests/Migrations/History/HistoryRepositoryTests.cs
  25. +139 −60 test/EntityFramework/UnitTests/Migrations/Infrastructure/EdmModelDifferTests.cs
  26. +1 −1 test/EntityFramework/UnitTests/Migrations/Sql/SqlServerMigrationSqlGeneratorTests.cs
  27. +1 −0 test/EntityFramework/UnitTests/UnitTests.csproj
  28. +19 −0 test/EntityFramework/UnitTests/Utilities/DbModelExtensionsTests.cs
  29. +12 −1 test/EntityFramework/UnitTests/Utilities/XDocumentExtensionsTests.cs
@@ -361,6 +361,7 @@
<Compile Include="Internal\ProviderConfig.cs" />
<Compile Include="Spatial\SpatialServicesLoader.cs" />
<Compile Include="Utilities\BoolExtensions.cs" />
+ <Compile Include="Utilities\DbModelExtensions.cs" />
<Compile Include="Utilities\DbProviderFactoryExtensions.cs" />
<Compile Include="Utilities\ExceptionExtensions.cs" />
<Compile Include="Core\Common\FieldMetadata.cs" />
@@ -5,6 +5,7 @@ namespace System.Data.Entity.Internal
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Migrations;
+ using System.Data.Entity.Migrations.Infrastructure;
using System.Data.Entity.Migrations.Sql;
using System.Diagnostics.Contracts;
@@ -37,7 +38,7 @@ public DatabaseCreator(Lazy<IDbDependencyResolver> resolver)
/// </summary>
public virtual void CreateDatabase(
InternalContext internalContext,
- Func<DbMigrationsConfiguration, DbContext, DbMigrator> createMigrator,
+ Func<DbMigrationsConfiguration, DbContext, MigratorBase> createMigrator,
ObjectContext objectContext)
{
Contract.Requires(internalContext != null);
@@ -112,7 +112,7 @@ internal DbMigrator(DbMigrationsConfiguration configuration, DbContext usersCont
_providerFactory = DbProviderServices.GetProviderFactory(connection);
_historyRepository
- = new HistoryRepository(_usersContextInfo.ConnectionString, _providerFactory, context.InternalContext.DefaultSchema);
+ = new HistoryRepository(_usersContextInfo.ConnectionString, _providerFactory);
_providerManifestToken = context.InternalContext.ModelProviderInfo != null
? context.InternalContext.ModelProviderInfo.ProviderManifestToken
@@ -135,12 +135,12 @@ internal DbMigrator(DbMigrationsConfiguration configuration, DbContext usersCont
}
}
- _emptyModel = new Lazy<XDocument>(
- () =>
- new DbModelBuilder().Build(
- new DbProviderInfo(
- _usersContextInfo.ConnectionProviderName,
- _providerManifestToken)).GetModel());
+ var providerInfo
+ = new DbProviderInfo(_usersContextInfo.ConnectionProviderName, _providerManifestToken);
+
+ _emptyModel = new Lazy<XDocument>(() => new DbModelBuilder().Build(providerInfo).GetModel());
+
+ _historyRepository.AppendHistoryModel(_currentModel, providerInfo);
}
/// <summary>
@@ -332,7 +332,7 @@ public override void Update(string targetMigration)
() => ExecuteOperations(
MigrationAssembly.CreateBootstrapMigrationId(),
_currentModel,
- new List<MigrationOperation>(),
+ _modelDiffer.Diff(_emptyModel.Value, _currentModel, true).Where(o => o.IsSystem),
false));
}
@@ -472,7 +472,9 @@ private bool IsModelOutOfDate(XDocument model, DbMigration lastMigration)
{
Contract.Requires(model != null);
- return _modelDiffer.Diff(GetLastModel(lastMigration), model).Any();
+ var sourceModel = GetLastModel(lastMigration);
+
+ return _modelDiffer.Diff(sourceModel, model, ReferenceEquals(sourceModel, _emptyModel.Value)).Any();
}
private XDocument GetLastModel(DbMigration lastMigration, string currentMigrationId = null)
@@ -509,31 +511,55 @@ internal override void Downgrade(IEnumerable<string> pendingMigrations)
Contract.Assert(targetModel != null);
+ var sourceModel = _historyRepository.GetModel(migrationId);
+
if (migration == null)
{
- var sourceModel = _historyRepository.GetModel(migrationId);
-
base.AutoMigrate(migrationId, sourceModel, targetModel, downgrading: true);
}
else
{
- base.RevertMigration(migrationId, migration, targetModel);
+ base.RevertMigration(migrationId, migration, sourceModel, targetModel);
}
}
}
- internal override void RevertMigration(string migrationId, DbMigration migration, XDocument targetModel)
+ internal override void RevertMigration(string migrationId, DbMigration migration, XDocument sourceModel, XDocument targetModel)
{
+ var includeSystemOps = false;
+
+ if (ReferenceEquals(targetModel, _emptyModel.Value))
+ {
+ includeSystemOps = true;
+
+ if (!sourceModel.HasSystemOperations())
+ {
+ // upgrade scenario, inject the history model
+ _historyRepository
+ .AppendHistoryModel(
+ sourceModel,
+ new DbProviderInfo(_usersContextInfo.ConnectionProviderName, _providerManifestToken));
+ }
+ }
+
+ var systemOperations
+ = _modelDiffer.Diff(sourceModel, targetModel, includeSystemOps)
+ .Where(o => o.IsSystem);
+
migration.Down();
- ExecuteOperations(migrationId, targetModel, migration.Operations.ToList(), downgrading: true);
+ ExecuteOperations(migrationId, targetModel, migration.Operations.Concat(systemOperations), downgrading: true);
}
internal override void ApplyMigration(DbMigration migration, DbMigration lastMigration)
{
var migrationMetadata = (IMigrationMetadata)migration;
var compressor = new ModelCompressor();
+ var lastModel = GetLastModel(lastMigration, migrationMetadata.Id);
+ var targetModel = compressor.Decompress(Convert.FromBase64String(migrationMetadata.Target));
+ var systemOperations = Enumerable.Empty<MigrationOperation>();
+
if (migrationMetadata.Source != null)
{
var sourceModel
@@ -543,24 +569,62 @@ var sourceModel
{
base.AutoMigrate(
migrationMetadata.Id.ToAutomaticMigrationId(),
- GetLastModel(lastMigration, migrationMetadata.Id),
+ lastModel,
sourceModel,
downgrading: false);
}
}
+ else
+ {
+ var includeSystemOps = false;
- migration.Up();
+ if (ReferenceEquals(lastModel, _emptyModel.Value))
+ {
+ includeSystemOps = true;
- var targetModel = compressor.Decompress(Convert.FromBase64String(migrationMetadata.Target));
+ if (!targetModel.HasSystemOperations())
+ {
+ // upgrade scenario, inject the history model
+ _historyRepository
+ .AppendHistoryModel(
+ targetModel,
+ new DbProviderInfo(_usersContextInfo.ConnectionProviderName, _providerManifestToken));
+ }
+ }
+
+ systemOperations
+ = _modelDiffer.Diff(lastModel, targetModel, includeSystemOps)
+ .Where(o => o.IsSystem);
+ }
+
+ migration.Up();
- ExecuteOperations(migrationMetadata.Id, targetModel, migration.Operations.ToList(), false);
+ ExecuteOperations(migrationMetadata.Id, targetModel, migration.Operations.Concat(systemOperations), false);
}
internal override void AutoMigrate(
string migrationId, XDocument sourceModel, XDocument targetModel, bool downgrading)
{
+ var includeSystemOps = false;
+
+ if (ReferenceEquals(downgrading ? targetModel : sourceModel, _emptyModel.Value))
+ {
+ includeSystemOps = true;
+
+ var appendableModel = downgrading ? sourceModel : targetModel;
+
+ if (!appendableModel.HasSystemOperations())
+ {
+ // upgrade scenario, inject the history model
+ _historyRepository
+ .AppendHistoryModel(
+ appendableModel,
+ new DbProviderInfo(_usersContextInfo.ConnectionProviderName, _providerManifestToken));
+ }
+ }
+
var operations
- = _modelDiffer.Diff(sourceModel, targetModel)
+ = _modelDiffer.Diff(sourceModel, targetModel, includeSystemOps)
.ToList();
if (!_configuration.AutomaticMigrationDataLossAllowed
@@ -594,25 +658,13 @@ var orderedOperations
.Concat(newTableForeignKeys)
.ToList();
- var isFirstMigration = IsFirstMigration(migrationId, downgrading);
-
- if (downgrading)
+ if (!downgrading)
{
- orderedOperations.Add(_historyRepository.CreateDeleteOperation(migrationId));
-
- if (isFirstMigration)
- {
- orderedOperations.Add(_historyRepository.CreateDropTableOperation(_modelDiffer));
- }
+ orderedOperations.Add(_historyRepository.CreateInsertOperation(migrationId, targetModel));
}
- else
+ else if (!operations.Any(o => o.IsSystem && o is DropTableOperation))
{
- if (isFirstMigration)
- {
- orderedOperations.Add(_historyRepository.CreateCreateTableOperation(_modelDiffer));
- }
-
- orderedOperations.Add(_historyRepository.CreateInsertOperation(migrationId, targetModel));
+ orderedOperations.Add(_historyRepository.CreateDeleteOperation(migrationId));
}
var migrationStatements = SqlGenerator.Generate(orderedOperations, _providerManifestToken);
@@ -627,6 +679,11 @@ var orderedOperations
}
base.ExecuteStatements(migrationStatements);
+
+ if (operations.Any(o => o.IsSystem))
+ {
+ _historyRepository.ResetExists();
+ }
}
internal override void ExecuteStatements(IEnumerable<MigrationStatement> migrationStatements)
@@ -655,6 +712,8 @@ internal override void ExecuteSql(DbTransaction transaction, MigrationStatement
return;
}
+ //Console.WriteLine(migrationStatement.Sql);
+
if (!migrationStatement.SuppressTransaction)
{
using (var command = transaction.Connection.CreateCommand())
@@ -756,6 +815,7 @@ internal override void EnsureDatabaseExists()
if (!Database.Exists(connection))
{
new DatabaseCreator().Create(connection);
+
_emptyMigrationNeeded = true;
}
else
@@ -770,41 +830,6 @@ internal override DbMigration GetMigration(string migrationId)
return _migrationAssembly.GetMigration(migrationId);
}
- internal override bool IsFirstMigrationIncludingAutomatics(string migrationId)
- {
- var firstMigrationId = _historyRepository.GetMigrationsSince(InitialDatabase).LastOrDefault();
-
- // If this is the first applied migration, return true; otherwise false
- return firstMigrationId == null
- || string.Equals(migrationId, firstMigrationId, StringComparison.Ordinal);
- }
-
- private bool IsFirstMigration(string migrationId, bool downgrading)
- {
- Contract.Requires(!string.IsNullOrWhiteSpace(migrationId));
- Contract.Assert(migrationId.IsValidMigrationId());
-
- if (downgrading)
- {
- var firstMigrationId = _historyRepository.GetMigrationsSince(InitialDatabase).LastOrDefault();
- Contract.Assert(firstMigrationId != null);
-
- return string.Equals(migrationId, firstMigrationId, StringComparison.Ordinal);
- }
-
- var firstExplicitMigrationId = _migrationAssembly.MigrationIds.FirstOrDefault();
-
- // If this comes before or is the first explicit migration...
- if (firstExplicitMigrationId == null
- || string.Equals(migrationId, firstExplicitMigrationId, StringComparison.Ordinal)
- || string.CompareOrdinal(migrationId, firstExplicitMigrationId) < 0)
- {
- return base.IsFirstMigrationIncludingAutomatics(migrationId);
- }
-
- return false;
- }
-
private DbConnection CreateConnection()
{
var connection = _providerFactory.CreateConnection();
@@ -26,6 +26,18 @@ internal static class EdmXNames
private static readonly XNamespace _ssdlNamespaceV3
= XNamespace.Get("http://schemas.microsoft.com/ado/2009/11/edm/ssdl");
+ private static readonly XNamespace _annotationsNamespace
+ = XNamespace.Get("http://schemas.microsoft.com/ado/2009/02/edm/annotation");
+
+ public static readonly XName IsSystem = _annotationsNamespace + "IsSystem";
+
+ public static string IsSystemAttribute(this XElement element)
+ {
+ Contract.Requires(element != null);
+
+ return (string)element.Attribute(IsSystem);
+ }
+
public static string ActionAttribute(this XElement element)
{
Contract.Requires(element != null);
@@ -215,6 +227,8 @@ public static class Msl
public static readonly IEnumerable<XName> ComplexPropertyNames = Names("ComplexProperty");
public static readonly IEnumerable<XName> ConditionNames = Names("Condition");
+ public static readonly IEnumerable<XName> EntityContainerMappingNames = Names("EntityContainerMapping");
+ public static readonly IEnumerable<XName> EntitySetMappingNames = Names("EntitySetMapping");
public static readonly IEnumerable<XName> EntityTypeMappingNames = Names("EntityTypeMapping");
[SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
@@ -240,6 +254,7 @@ public static class Ssdl
public static readonly IEnumerable<XName> AssociationNames = Names("Association");
public static readonly IEnumerable<XName> DependentNames = Names("Dependent");
public static readonly IEnumerable<XName> EndNames = Names("End");
+ public static readonly IEnumerable<XName> EntityContainerNames = Names("EntityContainer");
public static readonly IEnumerable<XName> EntitySetNames = Names("EntitySet");
public static readonly IEnumerable<XName> EntityTypeNames = Names("EntityType");
public static readonly IEnumerable<XName> KeyNames = Names("Key");
Oops, something went wrong.

0 comments on commit 9baca56

Please sign in to comment.