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

Migrations: Handle adding required properties #2519

Merged
merged 2 commits into from
Jul 3, 2015
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
2 changes: 1 addition & 1 deletion src/EntityFramework.Commands/Utilities/CSharpHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ public virtual string Literal([NotNull] IReadOnlyList<string> values) =>
? Literal(values[0])
: "new[] { " + string.Join(", ", values.Select(Literal)) + " }";

public virtual string Literal([NotNull] Enum value) => value.GetType().Name + "." + value;
public virtual string Literal([NotNull] Enum value) => Reference(value.GetType()) + "." + value;

public virtual string UnknownLiteral([CanBeNull] object value)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ public class ModelDiffer : IModelDiffer
typeof(AddUniqueConstraintOperation),
typeof(AlterColumnOperation),
typeof(AlterSequenceOperation),
typeof(CreateIndexOperation),
typeof(RestartSequenceOperation)
typeof(CreateIndexOperation)
};

private static readonly Type[] _renameOperationTypes =
Expand Down Expand Up @@ -74,7 +73,6 @@ protected virtual IReadOnlyList<MigrationOperation> Sort([NotNull] IEnumerable<M
var dropOperations = new List<MigrationOperation>();
var dropColumnOperations = new List<MigrationOperation>();
var dropTableOperations = new List<MigrationOperation>();
var dropSchemaOperations = new List<MigrationOperation>();
var createSchemaOperations = new List<MigrationOperation>();
var createSequenceOperations = new List<MigrationOperation>();
var createTableOperations = new Dictionary<string, CreateTableOperation>();
Expand Down Expand Up @@ -103,10 +101,6 @@ protected virtual IReadOnlyList<MigrationOperation> Sort([NotNull] IEnumerable<M
{
dropTableOperations.Add(operation);
}
else if (type == typeof(DropSchemaOperation))
{
dropSchemaOperations.Add(operation);
}
else if (type == typeof(CreateSchemaOperation))
{
createSchemaOperations.Add(operation);
Expand Down Expand Up @@ -180,7 +174,6 @@ protected virtual IReadOnlyList<MigrationOperation> Sort([NotNull] IEnumerable<M
.Concat(dropOperations)
.Concat(dropColumnOperations)
.Concat(dropTableOperations)
.Concat(dropSchemaOperations)
.Concat(createSchemaOperations)
.Concat(createSequenceOperations)
.Concat(sortedCreateTableOperations)
Expand All @@ -200,7 +193,8 @@ protected virtual IEnumerable<MigrationOperation> Diff([CanBeNull] IModel source
{
var diffContext = new ModelDifferContext();

return Diff(source.EntityTypes, target.EntityTypes, diffContext)
return Diff(GetSchemas(source), GetSchemas(target))
.Concat(Diff(source.EntityTypes, target.EntityTypes, diffContext))
.Concat(
Diff(MetadataExtensions.Extensions(source).Sequences, MetadataExtensions.Extensions(target).Sequences))
.Concat(
Expand All @@ -225,7 +219,8 @@ protected virtual IEnumerable<MigrationOperation> Add(IModel target)
{
var diffContext = new ModelDifferContext();

return target.EntityTypes.SelectMany(t => Add(t, diffContext))
return GetSchemas(target).SelectMany(Add)
.Concat(target.EntityTypes.SelectMany(t => Add(t, diffContext)))
.Concat(MetadataExtensions.Extensions(target).Sequences.SelectMany(Add))
.Concat(target.EntityTypes.SelectMany(t => t.GetForeignKeys()).SelectMany(k => Add(k, diffContext)));
}
Expand All @@ -236,6 +231,26 @@ protected virtual IEnumerable<MigrationOperation> Remove(IModel source) =>

#endregion

#region Schema

protected virtual IEnumerable<MigrationOperation> Diff(IEnumerable<string> source, IEnumerable<string> target)
=> DiffCollection(
source, target,
Diff, Add, Remove,
(s, t) => s == t);

protected virtual IEnumerable<MigrationOperation> Diff(string source, string target)
=> Enumerable.Empty<MigrationOperation>();

protected virtual IEnumerable<MigrationOperation> Add(string target)
{
yield return new CreateSchemaOperation { Name = target };
}

protected virtual IEnumerable<MigrationOperation> Remove(string source) => Enumerable.Empty<MigrationOperation>();

#endregion

#region IEntityType

protected virtual IEnumerable<MigrationOperation> Diff(
Expand Down Expand Up @@ -305,7 +320,7 @@ protected virtual IEnumerable<MigrationOperation> Add(IEntityType target, ModelD
};
CopyAnnotations(Annotations.For(target), createTableOperation);

createTableOperation.Columns.AddRange(target.GetProperties().SelectMany(Add).Cast<AddColumnOperation>());
createTableOperation.Columns.AddRange(target.GetProperties().SelectMany(p => Add(p, inline: true)).Cast<AddColumnOperation>());
var primaryKey = target.GetPrimaryKey();
createTableOperation.PrimaryKey = Add(primaryKey).Cast<AddPrimaryKeyOperation>().Single();
createTableOperation.UniqueConstraints.AddRange(
Expand Down Expand Up @@ -349,7 +364,7 @@ protected virtual IEnumerable<MigrationOperation> Diff(

return Diff(s, t);
},
Add,
t => Add(t),
Remove,
(s, t) => string.Equals(s.Name, t.Name, StringComparison.OrdinalIgnoreCase),
(s, t) => string.Equals(
Expand Down Expand Up @@ -411,7 +426,7 @@ protected virtual IEnumerable<MigrationOperation> Diff(IProperty source, IProper
}
}

protected virtual IEnumerable<MigrationOperation> Add(IProperty target)
protected virtual IEnumerable<MigrationOperation> Add(IProperty target, bool inline = false)
{
var targetExtensions = MetadataExtensions.Extensions(target);
var targetEntityTypeExtensions = MetadataExtensions.Extensions(target.EntityType);
Expand All @@ -423,7 +438,10 @@ protected virtual IEnumerable<MigrationOperation> Add(IProperty target)
Name = targetExtensions.Column,
Type = targetExtensions.ColumnType ?? TypeMapper.MapPropertyType(target).DefaultTypeName,
IsNullable = target.IsNullable,
DefaultValue = targetExtensions.DefaultValue,
DefaultValue = targetExtensions.DefaultValue
?? (inline || target.IsNullable
? null
: GetDefaultValue(target.ClrType)),
DefaultValueSql = targetExtensions.DefaultValueSql
};
CopyAnnotations(Annotations.For(target), operation);
Expand Down Expand Up @@ -827,5 +845,16 @@ protected virtual void CopyAnnotations(IEnumerable<IAnnotation> annotations, Ann
annotatable.AddAnnotation(annotation.Name, annotation.Value);
}
}

protected virtual IEnumerable<string> GetSchemas(IModel model)
=> model.EntityTypes.Select(t => MetadataExtensions.Extensions(t).Schema).Where(s => !string.IsNullOrEmpty(s))
.Distinct();

protected virtual object GetDefaultValue(Type type)
=> type == typeof(string)
? string.Empty
: type.IsArray
? Array.CreateInstance(type.GetElementType(), 0)
: type.UnwrapNullableType().GetDefaultValue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,18 +171,10 @@ public virtual void Generate(
.Append(")");
}

public virtual void Generate(
public abstract void Generate(
[NotNull] CreateSchemaOperation operation,
[CanBeNull] IModel model,
[NotNull] SqlBatchBuilder builder)
{
Check.NotNull(operation, nameof(operation));
Check.NotNull(builder, nameof(builder));

builder
.Append("CREATE SCHEMA ")
.Append(_sql.DelimitIdentifier(operation.Name));
}
[NotNull] SqlBatchBuilder builder);

public virtual void Generate(
[NotNull] CreateSequenceOperation operation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,12 @@ public virtual bool Exists()
}

var command = (SqlCommand)_connection.DbConnection.CreateCommand();
command.CommandText =
@"SELECT 1 FROM [INFORMATION_SCHEMA].[TABLES]
WHERE [TABLE_SCHEMA] = N'dbo' AND [TABLE_NAME] = '" + MigrationHistoryTableName + "' AND [TABLE_TYPE] = 'BASE TABLE'";
command.CommandText = "SELECT OBJECT_ID(N'dbo." + MigrationHistoryTableName + "');";

_connection.Open();
try
{
exists = command.ExecuteScalar() != null;
exists = command.ExecuteScalar() != DBNull.Value;
}
finally
{
Expand Down Expand Up @@ -109,7 +107,7 @@ public virtual string Create(bool ifNotExists)

if (ifNotExists)
{
builder.AppendLine("IF NOT EXISTS(SELECT * FROM [INFORMATION_SCHEMA].[TABLES] WHERE [TABLE_SCHEMA] = N'dbo' AND [TABLE_NAME] = '" + MigrationHistoryTableName + "' AND [TABLE_TYPE] = 'BASE TABLE')");
builder.AppendLine("IF OBJECT_ID(N'dbo." + MigrationHistoryTableName + "') IS NULL");
builder.IncrementIndent();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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.Text;
using JetBrains.Annotations;
using Microsoft.Data.Entity.Infrastructure;
Expand Down Expand Up @@ -138,6 +139,24 @@ public override void Generate(
}
}

public override void Generate(CreateSchemaOperation operation, IModel model, SqlBatchBuilder builder)
{
Check.NotNull(operation, nameof(operation));
Check.NotNull(builder, nameof(builder));

if (string.Equals(operation.Name, "DBO", StringComparison.OrdinalIgnoreCase))
{
return;
}

builder
.Append("IF SCHEMA_ID(N")
.Append(_sql.GenerateLiteral(operation.Name))
.Append(") IS NULL EXEC(N'CREATE SCHEMA ")
.Append(_sql.DelimitIdentifier(operation.Name))
.Append("')");
}

public virtual void Generate(
[NotNull] CreateDatabaseOperation operation,
[CanBeNull] IModel model,
Expand All @@ -150,9 +169,9 @@ public virtual void Generate(
.Append("CREATE DATABASE ")
.Append(_sql.DelimitIdentifier(operation.Name))
.EndBatch()
.Append("IF SERVERPROPERTY('EngineEdition') <> 5 EXECUTE sp_executesql N'ALTER DATABASE ")
.Append("IF SERVERPROPERTY('EngineEdition') <> 5 EXEC(N'ALTER DATABASE ")
.Append(_sql.DelimitIdentifier(operation.Name))
.Append(" SET READ_COMMITTED_SNAPSHOT ON'");
.Append(" SET READ_COMMITTED_SNAPSHOT ON')");
}

public virtual void Generate(
Expand All @@ -164,9 +183,9 @@ public virtual void Generate(
Check.NotNull(builder, nameof(builder));

builder
.Append("IF SERVERPROPERTY('EngineEdition') <> 5 EXECUTE sp_executesql N'ALTER DATABASE ")
.Append("IF SERVERPROPERTY('EngineEdition') <> 5 EXEC(N'ALTER DATABASE ")
.Append(_sql.DelimitIdentifier(operation.Name))
.Append(" SET SINGLE_USER WITH ROLLBACK IMMEDIATE'")
.Append(" SET SINGLE_USER WITH ROLLBACK IMMEDIATE')")
.EndBatch()
.Append("DROP DATABASE ")
.Append(_sql.DelimitIdentifier(operation.Name));
Expand Down Expand Up @@ -274,9 +293,9 @@ public virtual void Rename(
Check.NotNull(builder, nameof(builder));

builder
.Append("EXECUTE sp_rename ")
.Append("EXEC sp_rename N")
.Append(_sql.GenerateLiteral(name))
.Append(", ")
.Append(", N")
.Append(_sql.GenerateLiteral(newName));

if (type != null)
Expand Down
11 changes: 11 additions & 0 deletions test/EntityFramework.Commands.Tests/Utilities/CSharpHelperTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ void IDisposable.Dispose()
[InlineData(
(ushort)42,
"(ushort)42")]
[InlineData(
"",
"\"\"")]
[InlineData(
SomeEnum.Default,
"CSharpHelperTest.SomeEnum.Default")]
public void Literal_works(object value, string expected)
{
var literal = new CSharpHelper().UnknownLiteral(value);
Expand Down Expand Up @@ -210,5 +216,10 @@ public class DoubleNested
{
}
}

private enum SomeEnum
{
Default
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public void IsInteger_returns_true_only_for_integer_types()
Assert.False(typeof(bool?).IsInteger());
Assert.False(typeof(decimal).IsInteger());
Assert.False(typeof(float).IsInteger());
Assert.False(typeof(SomeEnum).IsInteger());
}

public class CtorFixture
Expand Down Expand Up @@ -391,6 +392,7 @@ private class Base

// ReSharper restore InconsistentNaming

[Fact]
public void Can_get_default_value_for_type()
{
Assert.Equal(false, typeof(bool).GetDefaultValue());
Expand All @@ -409,6 +411,7 @@ public void Can_get_default_value_for_type()
Assert.Equal(default(DateTime), typeof(DateTime).GetDefaultValue());
Assert.Equal(default(DateTimeOffset), typeof(DateTimeOffset).GetDefaultValue());
Assert.Equal(default(SomeStruct), typeof(SomeStruct).GetDefaultValue());
Assert.Equal(default(SomeEnum), typeof(SomeEnum).GetDefaultValue());
Assert.Equal(null, typeof(string).GetDefaultValue());
Assert.Equal(null, typeof(bool?).GetDefaultValue());
Assert.Equal(null, typeof(sbyte?).GetDefaultValue());
Expand All @@ -426,12 +429,18 @@ public void Can_get_default_value_for_type()
Assert.Equal(null, typeof(DateTime?).GetDefaultValue());
Assert.Equal(null, typeof(DateTimeOffset?).GetDefaultValue());
Assert.Equal(null, typeof(SomeStruct?).GetDefaultValue());
Assert.Equal(null, typeof(SomeEnum?).GetDefaultValue());
}

private struct SomeStruct
{
public int Value1 { get; set; }
public long Value2 { get; set; }
}

private enum SomeEnum
{
Default
}
}
}
Loading