Skip to content

Commit

Permalink
Use IRelationalMetadataExtensionProvider in ModelDiffer
Browse files Browse the repository at this point in the history
Fixes #1919 & fixes #1975
  • Loading branch information
bricelam committed May 28, 2015
1 parent a675bfe commit a2682a0
Show file tree
Hide file tree
Showing 7 changed files with 316 additions and 168 deletions.
252 changes: 163 additions & 89 deletions src/EntityFramework.Relational/Migrations/Infrastructure/ModelDiffer.cs

Large diffs are not rendered by default.

66 changes: 20 additions & 46 deletions src/EntityFramework.SqlServer/Migrations/SqlServerModelDiffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Sequence> _defaultSequence =
new LazyRef<Sequence>(() => new Sequence(Sequence.DefaultName));

protected override IEnumerable<MigrationOperation> 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<MigrationOperation> Diff(IProperty source, IProperty target)
Expand All @@ -69,15 +36,19 @@ protected override IEnumerable<MigrationOperation> 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);
}
Expand Down Expand Up @@ -184,12 +155,15 @@ protected override IEnumerable<MigrationOperation> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
<Compile Include="Metadata\SequenceTest.cs" />
<Compile Include="Migrations\Infrastructure\MigrationIdGeneratorTest.cs" />
<Compile Include="Migrations\Infrastructure\ModelDifferTest.cs" />
<Compile Include="Migrations\Infrastructure\ModelDifferTestBase.cs" />
<Compile Include="Migrations\Sql\MigrationSqlGeneratorTest.cs" />
<Compile Include="Migrations\Sql\MigrationSqlGeneratorTestBase.cs" />
<Compile Include="Model\RelationalTypeMappingTest.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -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<int>("ID");
x.Key("ID");
x.Property<int>("FK");
});
modelBuilder.Entity(
"Second",
x =>
{
x.Property<int>("ID");
x.Key("ID");
x.Property<int>("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);
});
}
}
}
Original file line number Diff line number Diff line change
@@ -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<ModelBuilder> buildSourceAction,
Action<ModelBuilder> buildTargetAction,
Action<IReadOnlyList<MigrationOperation>> 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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<Compile Include="Migrations\SqlServerHistoryRepositoryTest.cs" />
<Compile Include="Migrations\SqlServerMigrationSqlGeneratorTest.cs" />
<Compile Include="CommandConfigurationTests.cs" />
<Compile Include="Migrations\SqlServerModelDifferTest.cs" />
<Compile Include="SqlServerDataStoreCreatorTest.cs" />
<Compile Include="SqlServerEntityOptionsExtensionsTest.cs" />
<Compile Include="SqlServerDatabaseExtensionsTest.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -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<int>("Id");
x.Key("Id");
x.ForSqlServer().Table("People");
});
},
operations =>
{
Assert.Equal(1, operations.Count);
var addTableOperation = Assert.IsType<CreateTableOperation>(operations[0]);
Assert.Equal("People", addTableOperation.Name);
});
}

protected override ModelBuilder CreateModelBuilder() => new SqlServerModelBuilderFactory().CreateConventionBuilder();
protected override ModelDiffer CreateModelDiffer()
=> new SqlServerModelDiffer(new SqlServerTypeMapper(), new SqlServerMetadataExtensionProvider());
}
}

0 comments on commit a2682a0

Please sign in to comment.