diff --git a/src/EntityFramework.Relational/Migrations/Infrastructure/ModelDiffer.cs b/src/EntityFramework.Relational/Migrations/Infrastructure/ModelDiffer.cs index 9c53036f6ca..6888e4f9f65 100644 --- a/src/EntityFramework.Relational/Migrations/Infrastructure/ModelDiffer.cs +++ b/src/EntityFramework.Relational/Migrations/Infrastructure/ModelDiffer.cs @@ -44,14 +44,19 @@ public class ModelDiffer : IModelDiffer typeof(RenameSequenceOperation) }; - public ModelDiffer([NotNull] IRelationalTypeMapper typeMapper) + public ModelDiffer( + [NotNull] IRelationalTypeMapper typeMapper, + [NotNull] IRelationalMetadataExtensionProvider metadataExtensions) { Check.NotNull(typeMapper, nameof(typeMapper)); + Check.NotNull(metadataExtensions, nameof(metadataExtensions)); TypeMapper = typeMapper; + MetadataExtensions = metadataExtensions; } protected virtual IRelationalTypeMapper TypeMapper { get; } + protected virtual IRelationalMetadataExtensionProvider MetadataExtensions { get; } public virtual bool HasDifferences(IModel source, [CanBeNull] IModel target) => Diff(source, target).Any(); @@ -182,7 +187,8 @@ protected virtual IReadOnlyList Sort([NotNull] IEnumerable Diff([CanBeNull] IModel source, [CanBeNull] IModel target) => source != null && target != null ? Diff(source.EntityTypes, target.EntityTypes) - .Concat(Diff(source.Relational().Sequences, target.Relational().Sequences)) + .Concat( + Diff(MetadataExtensions.Extensions(source).Sequences, MetadataExtensions.Extensions(target).Sequences)) : target != null ? Add(target) : source != null @@ -191,11 +197,11 @@ protected virtual IReadOnlyList Sort([NotNull] IEnumerable Add(IModel target) => target.EntityTypes.SelectMany(Add) - .Concat(target.Relational().Sequences.SelectMany(Add)); + .Concat(MetadataExtensions.Extensions(target).Sequences.SelectMany(Add)); protected virtual IEnumerable Remove(IModel source) => source.EntityTypes.SelectMany(Remove) - .Concat(source.Relational().Sequences.SelectMany(Remove)); + .Concat(MetadataExtensions.Extensions(source).Sequences.SelectMany(Remove)); #endregion @@ -206,15 +212,18 @@ protected virtual IReadOnlyList Sort([NotNull] IEnumerable Diff(IEntityType source, IEntityType target) { - if (source.Relational().Schema != target.Relational().Schema - || source.Relational().Table != target.Relational().Table) + var sourceExtensions = MetadataExtensions.Extensions(source); + var targetExtensions = MetadataExtensions.Extensions(target); + + if (sourceExtensions.Schema != targetExtensions.Schema + || sourceExtensions.Table != targetExtensions.Table) { yield return new RenameTableOperation { - Schema = source.Relational().Schema, - Name = source.Relational().Table, - NewSchema = target.Relational().Schema, - NewName = target.Relational().Table + Schema = sourceExtensions.Schema, + Name = sourceExtensions.Table, + NewSchema = targetExtensions.Schema, + NewName = targetExtensions.Table }; } @@ -234,6 +243,8 @@ protected virtual IEnumerable Diff(IEntityType source, IEnti protected virtual IEntityType TryMatch(IEntityType source, IEnumerable targets) { + var sourceExtensions = MetadataExtensions.Extensions(source); + var candidates = new Dictionary(); foreach (var target in targets) { @@ -241,14 +252,16 @@ protected virtual IEntityType TryMatch(IEntityType source, IEnumerable Add(IEntityType target) { + var targetExtensions = MetadataExtensions.Extensions(target); + var createTableOperation = new CreateTableOperation { - Schema = target.Relational().Schema, - Name = target.Relational().Table + Schema = targetExtensions.Schema, + Name = targetExtensions.Table }; createTableOperation.Columns.AddRange(target.GetProperties().SelectMany(Add).Cast()); @@ -293,10 +308,12 @@ protected virtual IEnumerable Add(IEntityType target) protected virtual IEnumerable Remove(IEntityType source) { + var sourceExtensions = MetadataExtensions.Extensions(source); + yield return new DropTableOperation { - Schema = source.Relational().Schema, - Name = source.Relational().Table + Schema = sourceExtensions.Schema, + Name = sourceExtensions.Table }; } @@ -309,14 +326,18 @@ protected virtual IEnumerable Remove(IEntityType source) protected virtual IEnumerable Diff(IProperty source, IProperty target) { - if (source.Relational().Column != target.Relational().Column) + var sourceExtensions = MetadataExtensions.Extensions(source); + var sourceEntityTypeExtensions = MetadataExtensions.Extensions(source.EntityType); + var targetExtensions = MetadataExtensions.Extensions(target); + + if (sourceExtensions.Column != targetExtensions.Column) { yield return new RenameColumnOperation { - Schema = source.EntityType.Relational().Schema, - Table = source.EntityType.Relational().Table, - Name = source.Relational().Column, - NewName = target.Relational().Column + Schema = sourceEntityTypeExtensions.Schema, + Table = sourceEntityTypeExtensions.Table, + Name = sourceExtensions.Column, + NewName = targetExtensions.Column }; } @@ -330,8 +351,8 @@ protected virtual IEnumerable Diff(IProperty source, IProper if (isNullableChanged || source.StoreGeneratedPattern != target.StoreGeneratedPattern || columnTypeChanged - || source.Relational().DefaultExpression != target.Relational().DefaultExpression - || source.Relational().DefaultValue != target.Relational().DefaultValue) + || sourceExtensions.DefaultExpression != targetExtensions.DefaultExpression + || sourceExtensions.DefaultValue != targetExtensions.DefaultValue) { var isDestructiveChange = (isNullableChanged && source.IsNullable == true) // TODO: Detect type narrowing @@ -339,13 +360,13 @@ protected virtual IEnumerable Diff(IProperty source, IProper yield return new AlterColumnOperation { - Schema = source.EntityType.Relational().Schema, - Table = source.EntityType.Relational().Table, - Name = source.Relational().Column, + Schema = sourceEntityTypeExtensions.Schema, + Table = sourceEntityTypeExtensions.Table, + Name = sourceExtensions.Column, Type = targetColumnType, IsNullable = target.IsNullable, - DefaultValue = target.Relational().DefaultValue, - DefaultExpression = target.Relational().DefaultExpression, + DefaultValue = targetExtensions.DefaultValue, + DefaultExpression = targetExtensions.DefaultExpression, IsDestructiveChange = isDestructiveChange }; } @@ -353,6 +374,8 @@ protected virtual IEnumerable Diff(IProperty source, IProper protected virtual IProperty TryMatch(IProperty source, IEnumerable targets) { + var sourceExtensions = MetadataExtensions.Extensions(source); + var candidates = new List(); foreach (var target in targets) { @@ -360,9 +383,11 @@ protected virtual IProperty TryMatch(IProperty source, IEnumerable ta { return target; } + + var targetExtensions = MetadataExtensions.Extensions(target); if (string.Equals( - source.Relational().Column, - target.Relational().Column, + sourceExtensions.Column, + targetExtensions.Column, StringComparison.OrdinalIgnoreCase)) { candidates.Add(target); @@ -374,25 +399,31 @@ protected virtual IProperty TryMatch(IProperty source, IEnumerable ta protected virtual IEnumerable Add(IProperty target) { + var targetExtensions = MetadataExtensions.Extensions(target); + var targetEntityTypeExtensions = MetadataExtensions.Extensions(target.EntityType); + yield return new AddColumnOperation { - Schema = target.EntityType.Relational().Schema, - Table = target.EntityType.Relational().Table, - Name = target.Relational().Column, + Schema = targetEntityTypeExtensions.Schema, + Table = targetEntityTypeExtensions.Table, + Name = targetExtensions.Column, Type = TypeMapper.GetTypeMapping(target).StoreTypeName, IsNullable = target.IsNullable, - DefaultValue = target.Relational().DefaultValue, - DefaultExpression = target.Relational().DefaultExpression + DefaultValue = targetExtensions.DefaultValue, + DefaultExpression = targetExtensions.DefaultExpression }; } protected virtual IEnumerable Remove(IProperty source) { + var sourceExtensions = MetadataExtensions.Extensions(source); + var sourceEntityTypeExtensions = MetadataExtensions.Extensions(source.EntityType); + yield return new DropColumnOperation { - Schema = source.EntityType.Relational().Schema, - Table = source.EntityType.Relational().Table, - Name = source.Relational().Column + Schema = sourceEntityTypeExtensions.Schema, + Table = sourceEntityTypeExtensions.Table, + Name = sourceExtensions.Column }; } @@ -408,9 +439,12 @@ protected virtual IEnumerable Diff(IKey source, IKey target) if (source != null && target != null) { - if (source.Relational().Name != target.Relational().Name - || !source.Properties.Select(p => p.Relational().Column).SequenceEqual( - target.Properties.Select(p => p.Relational().Column))) + var sourceExtensions = MetadataExtensions.Extensions(source); + var targetExtensions = MetadataExtensions.Extensions(target); + + if (sourceExtensions.Name != targetExtensions.Name + || !source.Properties.Select(p => MetadataExtensions.Extensions(p).Column).SequenceEqual( + target.Properties.Select(p => MetadataExtensions.Extensions(p).Column))) { return Remove(source) .Concat(Add(target)); @@ -430,9 +464,12 @@ protected virtual IEnumerable Diff(IKey source, IKey target) protected virtual IKey TryMatch(IKey source, IEnumerable targets) { + var sourceExtensions = MetadataExtensions.Extensions(source); + foreach (var target in targets) { - if (string.Equals(source.Relational().Name, target.Relational().Name, StringComparison.OrdinalIgnoreCase)) + var targetExtensions = MetadataExtensions.Extensions(target); + if (string.Equals(sourceExtensions.Name, targetExtensions.Name, StringComparison.OrdinalIgnoreCase)) { return target; } @@ -443,46 +480,52 @@ protected virtual IKey TryMatch(IKey source, IEnumerable targets) protected virtual IEnumerable Add(IKey target) { + var targetExtensions = MetadataExtensions.Extensions(target); + var targetEntityTypeExtensions = MetadataExtensions.Extensions(target.EntityType); + if (target.IsPrimaryKey()) { yield return new AddPrimaryKeyOperation { - Schema = target.EntityType.Relational().Schema, - Table = target.EntityType.Relational().Table, - Name = target.Relational().Name, - Columns = target.Properties.Select(p => p.Relational().Column).ToArray() + Schema = targetEntityTypeExtensions.Schema, + Table = targetEntityTypeExtensions.Table, + Name = targetExtensions.Name, + Columns = GetColumnNames(target.Properties) }; } else { yield return new AddUniqueConstraintOperation { - Schema = target.EntityType.Relational().Schema, - Table = target.EntityType.Relational().Table, - Name = target.Relational().Name, - Columns = target.Properties.Select(p => p.Relational().Column).ToArray() + Schema = targetEntityTypeExtensions.Schema, + Table = targetEntityTypeExtensions.Table, + Name = targetExtensions.Name, + Columns = GetColumnNames(target.Properties) }; } } protected virtual IEnumerable Remove(IKey source) { + var sourceExtensions = MetadataExtensions.Extensions(source); + var sourceEntityTypeExtensions = MetadataExtensions.Extensions(source.EntityType); + if (source.IsPrimaryKey()) { yield return new DropPrimaryKeyOperation { - Schema = source.EntityType.Relational().Schema, - Table = source.EntityType.Relational().Table, - Name = source.Relational().Name + Schema = sourceEntityTypeExtensions.Schema, + Table = sourceEntityTypeExtensions.Table, + Name = sourceExtensions.Name }; } else { yield return new DropUniqueConstraintOperation { - Schema = source.EntityType.Relational().Schema, - Table = source.EntityType.Relational().Table, - Name = source.Relational().Name + Schema = sourceEntityTypeExtensions.Schema, + Table = sourceEntityTypeExtensions.Table, + Name = sourceExtensions.Name }; } } @@ -496,12 +539,17 @@ protected virtual IEnumerable Remove(IKey source) protected virtual IEnumerable Diff(IForeignKey source, IForeignKey target) { - if (source.Relational().Name != target.Relational().Name - || !source.Properties.Select(p => p.Relational().Column).SequenceEqual( - target.Properties.Select(p => p.Relational().Column)) - || source.PrincipalEntityType.Relational().Table != target.PrincipalEntityType.Relational().Table - || !source.PrincipalKey.Properties.Select(p => p.Relational().Column).SequenceEqual( - target.PrincipalKey.Properties.Select(p => p.Relational().Column))) + var sourceExtensions = MetadataExtensions.Extensions(source); + var sourcePrincipalEntityTypeExtensions = MetadataExtensions.Extensions(source.PrincipalEntityType); + var targetExtensions = MetadataExtensions.Extensions(target); + var targetPrincipalEntityTypeExtensions = MetadataExtensions.Extensions(target.PrincipalEntityType); + + if (sourceExtensions.Name != targetExtensions.Name + || !source.Properties.Select(p => MetadataExtensions.Extensions(p).Column).SequenceEqual( + target.Properties.Select(p => MetadataExtensions.Extensions(p).Column)) + || sourcePrincipalEntityTypeExtensions.Table != targetPrincipalEntityTypeExtensions.Table + || !source.PrincipalKey.Properties.Select(p => MetadataExtensions.Extensions(p).Column).SequenceEqual( + target.PrincipalKey.Properties.Select(p => MetadataExtensions.Extensions(p).Column))) { return Remove(source) .Concat(Add(target)); @@ -512,9 +560,12 @@ protected virtual IEnumerable Diff(IForeignKey source, IFore protected virtual IForeignKey TryMatch(IForeignKey source, IEnumerable targets) { + var sourceExtensions = MetadataExtensions.Extensions(source); + foreach (var target in targets) { - if (string.Equals(source.Relational().Name, target.Relational().Name, StringComparison.OrdinalIgnoreCase)) + var targetExtensions = MetadataExtensions.Extensions(target); + if (string.Equals(sourceExtensions.Name, targetExtensions.Name, StringComparison.OrdinalIgnoreCase)) { return target; } @@ -525,26 +576,33 @@ protected virtual IForeignKey TryMatch(IForeignKey source, IEnumerable Add(IForeignKey target) { + var targetExtensions = MetadataExtensions.Extensions(target); + var targetEntityTypeExtensions = MetadataExtensions.Extensions(target.EntityType); + var targetPrincipalEntityTypeExtensions = MetadataExtensions.Extensions(target.PrincipalEntityType); + // TODO: Set CascadeOnDelete (See #1084) yield return new AddForeignKeyOperation { - Schema = target.EntityType.Relational().Schema, - Table = target.EntityType.Relational().Table, - Name = target.Relational().Name, - Columns = target.Properties.Select(p => p.Relational().Column).ToArray(), - ReferencedSchema = target.PrincipalEntityType.Relational().Schema, - ReferencedTable = target.PrincipalEntityType.Relational().Table, - ReferencedColumns = target.PrincipalKey.Properties.Select(p => p.Relational().Column).ToArray() + Schema = targetEntityTypeExtensions.Schema, + Table = targetEntityTypeExtensions.Table, + Name = targetExtensions.Name, + Columns = GetColumnNames(target.Properties), + ReferencedSchema = targetPrincipalEntityTypeExtensions.Schema, + ReferencedTable = targetPrincipalEntityTypeExtensions.Table, + ReferencedColumns = GetColumnNames(target.PrincipalKey.Properties) }; } protected virtual IEnumerable Remove(IForeignKey source) { + var sourceExtensions = MetadataExtensions.Extensions(source); + var sourceEntityTypeExtensions = MetadataExtensions.Extensions(source.EntityType); + yield return new DropForeignKeyOperation { - Schema = source.EntityType.Relational().Schema, - Table = source.EntityType.Relational().Table, - Name = source.Relational().Name + Schema = sourceEntityTypeExtensions.Schema, + Table = sourceEntityTypeExtensions.Table, + Name = sourceExtensions.Name }; } @@ -557,22 +615,26 @@ protected virtual IEnumerable Remove(IForeignKey source) protected virtual IEnumerable Diff(IIndex source, IIndex target) { - var sourceName = source.Relational().Name; - var targetName = target.Relational().Name; + var sourceExtensions = MetadataExtensions.Extensions(source); + var sourceEntityTypeExtensions = MetadataExtensions.Extensions(source.EntityType); + var targetExtensions = MetadataExtensions.Extensions(target); + + var sourceName = sourceExtensions.Name; + var targetName = targetExtensions.Name; if (sourceName != targetName) { yield return new RenameIndexOperation { - Schema = source.EntityType.Relational().Schema, - Table = source.EntityType.Relational().Table, + Schema = sourceEntityTypeExtensions.Schema, + Table = sourceEntityTypeExtensions.Table, Name = sourceName, NewName = targetName }; } - if (!source.Properties.Select(p => p.Relational().Column).SequenceEqual( - target.Properties.Select(p => p.Relational().Column)) + if (!source.Properties.Select(p => MetadataExtensions.Extensions(p).Column).SequenceEqual( + target.Properties.Select(p => MetadataExtensions.Extensions(p).Column)) || source.IsUnique != target.IsUnique) { var operations = Remove(source) @@ -586,9 +648,12 @@ protected virtual IEnumerable Diff(IIndex source, IIndex tar protected virtual IIndex TryMatch(IIndex source, IEnumerable targets) { + var sourceExtensions = MetadataExtensions.Extensions(source); + foreach (var target in targets) { - if (string.Equals(source.Relational().Name, target.Relational().Name, StringComparison.OrdinalIgnoreCase)) + var targetExtensions = MetadataExtensions.Extensions(target); + if (string.Equals(sourceExtensions.Name, targetExtensions.Name, StringComparison.OrdinalIgnoreCase)) { return target; } @@ -599,23 +664,29 @@ protected virtual IIndex TryMatch(IIndex source, IEnumerable targets) protected virtual IEnumerable Add(IIndex target) { + var targetExtensions = MetadataExtensions.Extensions(target); + var targetEntityTypeExtensions = MetadataExtensions.Extensions(target.EntityType); + yield return new CreateIndexOperation { - Name = target.Relational().Name, - Schema = target.EntityType.Relational().Schema, - Table = target.EntityType.Relational().Table, - Columns = target.Properties.Select(p => p.Relational().Column).ToArray(), + Name = targetExtensions.Name, + Schema = targetEntityTypeExtensions.Schema, + Table = targetEntityTypeExtensions.Table, + Columns = GetColumnNames(target.Properties), IsUnique = target.IsUnique }; } protected virtual IEnumerable Remove(IIndex source) { + var sourceExtensions = MetadataExtensions.Extensions(source); + var sourceEntityTypeExtensions = MetadataExtensions.Extensions(source.EntityType); + yield return new DropIndexOperation { - Name = source.Relational().Name, - Schema = source.EntityType.Relational().Schema, - Table = source.EntityType.Relational().Table + Name = sourceExtensions.Name, + Schema = sourceEntityTypeExtensions.Schema, + Table = sourceEntityTypeExtensions.Table }; } @@ -738,5 +809,8 @@ protected virtual IEnumerable Remove(ISequence source) yield return operation; } } + + protected virtual string[] GetColumnNames(IEnumerable properties) + => properties.Select(p => MetadataExtensions.Extensions(p).Column).ToArray(); } } diff --git a/src/EntityFramework.SqlServer/Migrations/SqlServerModelDiffer.cs b/src/EntityFramework.SqlServer/Migrations/SqlServerModelDiffer.cs index ab56159d2c5..f8a7f78be91 100644 --- a/src/EntityFramework.SqlServer/Migrations/SqlServerModelDiffer.cs +++ b/src/EntityFramework.SqlServer/Migrations/SqlServerModelDiffer.cs @@ -10,51 +10,18 @@ using Microsoft.Data.Entity.Relational.Migrations.Infrastructure; using Microsoft.Data.Entity.Relational.Migrations.Operations; using Microsoft.Data.Entity.SqlServer.Metadata; -using Microsoft.Data.Entity.Utilities; namespace Microsoft.Data.Entity.SqlServer.Migrations { public class SqlServerModelDiffer : ModelDiffer { - public SqlServerModelDiffer([NotNull] IRelationalTypeMapper typeMapper) - : base(typeMapper) + public SqlServerModelDiffer( + [NotNull] IRelationalTypeMapper typeMapper, + [NotNull] IRelationalMetadataExtensionProvider metadataExtensions) + : base(typeMapper, metadataExtensions) { } - #region IModel - - private static readonly LazyRef _defaultSequence = - new LazyRef(() => new Sequence(Sequence.DefaultName)); - - protected override IEnumerable Diff([CanBeNull] IModel source, [CanBeNull] IModel target) - { - var operations = base.Diff(source, target); - - // TODO: Remove when the default sequence is added to the model (See #1568) - var sourceUsesDefaultSequence = DefaultSequenceUsed(source); - var targetUsesDefaultSequence = DefaultSequenceUsed(target); - if (sourceUsesDefaultSequence == false && targetUsesDefaultSequence) - { - operations = operations.Concat(Add(_defaultSequence.Value)); - } - else if (sourceUsesDefaultSequence && targetUsesDefaultSequence == false) - { - operations = operations.Concat(Remove(_defaultSequence.Value)); - } - - return operations; - } - - private bool DefaultSequenceUsed(IModel model) => - model != null - && (model.SqlServer().DefaultSequenceName == null || model.SqlServer().DefaultSequenceName == Sequence.DefaultName) - && (model.SqlServer().ValueGenerationStrategy == SqlServerValueGenerationStrategy.Sequence - || model.EntityTypes.SelectMany(t => t.GetProperties()).Any( - p => p.SqlServer().ValueGenerationStrategy == SqlServerValueGenerationStrategy.Sequence - && (p.SqlServer().SequenceName == null || p.SqlServer().SequenceName == Sequence.DefaultName))); - - #endregion - #region IProperty protected override IEnumerable Diff(IProperty source, IProperty target) @@ -69,15 +36,19 @@ protected override IEnumerable Diff(IProperty source, IPrope && (source.SqlServer().ComputedExpression != target.SqlServer().ComputedExpression || sourceValueGenerationStrategy != targetValueGenerationStrategy)) { + var sourceExtensions = MetadataExtensions.Extensions(source); + var sourceEntityTypeExtensions = MetadataExtensions.Extensions(source.EntityType); + var targetExtensions = MetadataExtensions.Extensions(target); + alterColumnOperation = new AlterColumnOperation { - Schema = source.EntityType.Relational().Schema, - Table = source.EntityType.Relational().Table, - Name = source.Relational().Column, + Schema = sourceEntityTypeExtensions.Schema, + Table = sourceEntityTypeExtensions.Table, + Name = sourceExtensions.Column, Type = TypeMapper.GetTypeMapping(target).StoreTypeName, IsNullable = target.IsNullable, - DefaultValue = target.Relational().DefaultValue, - DefaultExpression = target.Relational().DefaultExpression + DefaultValue = targetExtensions.DefaultValue, + DefaultExpression = targetExtensions.DefaultExpression }; operations.Add(alterColumnOperation); } @@ -184,12 +155,15 @@ protected override IEnumerable Diff(IIndex source, IIndex ta { operations.AddRange(Remove(source)); + var targetExtensions = MetadataExtensions.Extensions(target); + var targetEntityTypeExtensions = MetadataExtensions.Extensions(target.EntityType); + createIndexOperation = new CreateIndexOperation { - Name = target.Relational().Name, - Schema = target.EntityType.Relational().Schema, - Table = target.EntityType.Relational().Table, - Columns = target.Properties.Select(p => p.Relational().Column).ToArray(), + Name = targetExtensions.Name, + Schema = targetEntityTypeExtensions.Schema, + Table = targetEntityTypeExtensions.Table, + Columns = GetColumnNames(target.Properties), IsUnique = target.IsUnique }; operations.Add(createIndexOperation); diff --git a/test/EntityFramework.Relational.Tests/EntityFramework.Relational.Tests.csproj b/test/EntityFramework.Relational.Tests/EntityFramework.Relational.Tests.csproj index 8bb341ba283..a6cbcb2e540 100644 --- a/test/EntityFramework.Relational.Tests/EntityFramework.Relational.Tests.csproj +++ b/test/EntityFramework.Relational.Tests/EntityFramework.Relational.Tests.csproj @@ -77,6 +77,7 @@ + diff --git a/test/EntityFramework.Relational.Tests/Migrations/Infrastructure/ModelDifferTest.cs b/test/EntityFramework.Relational.Tests/Migrations/Infrastructure/ModelDifferTest.cs index 415464b4a46..92559663574 100644 --- a/test/EntityFramework.Relational.Tests/Migrations/Infrastructure/ModelDifferTest.cs +++ b/test/EntityFramework.Relational.Tests/Migrations/Infrastructure/ModelDifferTest.cs @@ -1,47 +1,57 @@ // 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 Microsoft.Data.Entity.Relational.Migrations.Infrastructure; using Microsoft.Data.Entity.Relational.Migrations.Operations; using Xunit; -namespace Microsoft.Data.Entity.Relational.Tests.Migrations.Infrastructure +namespace Microsoft.Data.Entity.Relational.Migrations.Infrastructure { - public class ModelDifferTest + public class ModelDifferTest : ModelDifferTestBase { [Fact] public void Model_differ_breaks_foreign_key_cycles() { - var model = new Entity.Metadata.Model(); - - var firstType = model.AddEntityType("First"); - var firstKey = firstType.SetPrimaryKey(firstType.AddProperty("ID", typeof(int), true)); - var firstFk = firstType.AddProperty("FK", typeof(int), true); - - var secondType = model.AddEntityType("Second"); - var secondKey = secondType.SetPrimaryKey(secondType.AddProperty("ID", typeof(int), true)); - var secondFk = secondType.AddProperty("FK", typeof(int), true); - - firstType.AddForeignKey(firstFk, secondKey); - secondType.AddForeignKey(secondFk, firstKey); - - var modelDiffer = new ModelDiffer(new RelationalTypeMapper()); - - var result = modelDiffer.GetDifferences(null, model); - - Assert.Equal(3, result.Count); - - var firstOperation = result[0] as CreateTableOperation; - var secondOperation = result[1] as CreateTableOperation; - var thirdOperation = result[2] as AddForeignKeyOperation; - - Assert.NotNull(firstOperation); - Assert.NotNull(secondOperation); - Assert.NotNull(thirdOperation); - - Assert.Equal(0, firstOperation.ForeignKeys.Count); - Assert.Equal(1, secondOperation.ForeignKeys.Count); - Assert.Equal(firstOperation.Name, thirdOperation.Table); + Execute( + _ => { }, + modelBuilder => + { + modelBuilder.Entity( + "First", + x => + { + x.Property("ID"); + x.Key("ID"); + x.Property("FK"); + }); + + modelBuilder.Entity( + "Second", + x => + { + x.Property("ID"); + x.Key("ID"); + x.Property("FK"); + }); + + modelBuilder.Entity("First").Reference("Second").InverseCollection().ForeignKey("FK").PrincipalKey("ID"); + modelBuilder.Entity("Second").Reference("First").InverseCollection().ForeignKey("FK").PrincipalKey("ID"); + }, + result => + { + Assert.Equal(3, result.Count); + + var firstOperation = result[0] as CreateTableOperation; + var secondOperation = result[1] as CreateTableOperation; + var thirdOperation = result[2] as AddForeignKeyOperation; + + Assert.NotNull(firstOperation); + Assert.NotNull(secondOperation); + Assert.NotNull(thirdOperation); + + Assert.Equal(0, firstOperation.ForeignKeys.Count); + Assert.Equal(1, secondOperation.ForeignKeys.Count); + Assert.Equal(firstOperation.Name, thirdOperation.Table); + }); } } } diff --git a/test/EntityFramework.Relational.Tests/Migrations/Infrastructure/ModelDifferTestBase.cs b/test/EntityFramework.Relational.Tests/Migrations/Infrastructure/ModelDifferTestBase.cs new file mode 100644 index 00000000000..d69f3e9457c --- /dev/null +++ b/test/EntityFramework.Relational.Tests/Migrations/Infrastructure/ModelDifferTestBase.cs @@ -0,0 +1,46 @@ +// 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 System.Collections.Generic; +using Microsoft.Data.Entity.Metadata; +using Microsoft.Data.Entity.Metadata.Builders; +using Microsoft.Data.Entity.Relational.Metadata; +using Microsoft.Data.Entity.Relational.Migrations.Operations; + +namespace Microsoft.Data.Entity.Relational.Migrations.Infrastructure +{ + public class ModelDifferTestBase + { + protected void Execute( + Action buildSourceAction, + Action buildTargetAction, + Action> assertAction) + { + var sourceModelBuilder = CreateModelBuilder(); + buildSourceAction(sourceModelBuilder); + + var targetModelBuilder = CreateModelBuilder(); + buildTargetAction(targetModelBuilder); + + var modelDiffer = CreateModelDiffer(); + + var operations = modelDiffer.GetDifferences(sourceModelBuilder.Model, targetModelBuilder.Model); + + assertAction(operations); + } + + protected virtual ModelBuilder CreateModelBuilder() => new ModelBuilderFactory().CreateConventionBuilder(); + protected virtual ModelDiffer CreateModelDiffer() => new ModelDiffer(new RelationalTypeMapper(), new TestMetadataExtensionProvider()); + + private class TestMetadataExtensionProvider : IRelationalMetadataExtensionProvider + { + public IRelationalEntityTypeExtensions Extensions(IEntityType entityType) => entityType.Relational(); + public IRelationalForeignKeyExtensions Extensions(IForeignKey foreignKey) => foreignKey.Relational(); + public IRelationalIndexExtensions Extensions(IIndex index) => index.Relational(); + public IRelationalKeyExtensions Extensions(IKey key) => key.Relational(); + public IRelationalModelExtensions Extensions(IModel model) => model.Relational(); + public IRelationalPropertyExtensions Extensions(IProperty property) => property.Relational(); + } + } +} diff --git a/test/EntityFramework.SqlServer.Tests/EntityFramework.SqlServer.Tests.csproj b/test/EntityFramework.SqlServer.Tests/EntityFramework.SqlServer.Tests.csproj index 1fc0aab42c4..c996a990788 100644 --- a/test/EntityFramework.SqlServer.Tests/EntityFramework.SqlServer.Tests.csproj +++ b/test/EntityFramework.SqlServer.Tests/EntityFramework.SqlServer.Tests.csproj @@ -75,6 +75,7 @@ + diff --git a/test/EntityFramework.SqlServer.Tests/Migrations/SqlServerModelDifferTest.cs b/test/EntityFramework.SqlServer.Tests/Migrations/SqlServerModelDifferTest.cs new file mode 100644 index 00000000000..d58e2314620 --- /dev/null +++ b/test/EntityFramework.SqlServer.Tests/Migrations/SqlServerModelDifferTest.cs @@ -0,0 +1,42 @@ +// 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 Microsoft.Data.Entity.Relational.Migrations.Infrastructure; +using Microsoft.Data.Entity.Relational.Migrations.Operations; +using Microsoft.Data.Entity.SqlServer.Metadata; +using Xunit; + +namespace Microsoft.Data.Entity.SqlServer.Migrations +{ + public class SqlServerModelDifferTest : ModelDifferTestBase + { + [Fact] + public void Can_use_provider_overrides() + { + Execute( + _ => { }, + modelBuilder => + { + modelBuilder.Entity( + "Person", + x => + { + x.Property("Id"); + x.Key("Id"); + x.ForSqlServer().Table("People"); + }); + }, + operations => + { + Assert.Equal(1, operations.Count); + + var addTableOperation = Assert.IsType(operations[0]); + Assert.Equal("People", addTableOperation.Name); + }); + } + + protected override ModelBuilder CreateModelBuilder() => new SqlServerModelBuilderFactory().CreateConventionBuilder(); + protected override ModelDiffer CreateModelDiffer() + => new SqlServerModelDiffer(new SqlServerTypeMapper(), new SqlServerMetadataExtensionProvider()); + } +}