Skip to content

Commit

Permalink
Use ContextTypeAttribute during migration discovery
Browse files Browse the repository at this point in the history
  • Loading branch information
bricelam committed Sep 18, 2014
1 parent 14deb62 commit 5c6be5f
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 39 deletions.
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 System.Linq;
using JetBrains.Annotations;
Expand All @@ -22,6 +23,7 @@ public class CSharpModelCodeGenerator : ModelCodeGenerator
string @namespace,
string className,
IModel model,
Type contextType,
IndentedStringBuilder stringBuilder)
{
Check.NotEmpty(className, "className");
Expand All @@ -30,7 +32,7 @@ public class CSharpModelCodeGenerator : ModelCodeGenerator
Check.NotNull(stringBuilder, "stringBuilder");

// TODO: Consider namespace ordering, for example putting System namespaces first
foreach (var ns in GetNamespaces(model).OrderBy(n => n).Distinct())
foreach (var ns in GetNamespaces(model, contextType).OrderBy(n => n).Distinct())
{
stringBuilder
.Append("using ")
Expand All @@ -47,6 +49,9 @@ public class CSharpModelCodeGenerator : ModelCodeGenerator
using (stringBuilder.Indent())
{
stringBuilder
.Append("[ContextType(typeof(")
.Append(contextType.GetNestedName())
.AppendLine("))]")
.Append("public class ")
.Append(className)
.AppendLine(" : ModelSnapshot")
Expand Down
Expand Up @@ -81,7 +81,7 @@ public virtual ScaffoldedMigration ScaffoldMigration([NotNull] string migrationN
var snapshotModelCode = new IndentedStringBuilder();

ScaffoldMigration(migration, migrationCode, migrationMetadataCode);
ScaffoldSnapshotModel(migration.TargetModel, snapshotModelCode);
ScaffoldSnapshotModel(migration.TargetModel, migration.ContextType, snapshotModelCode);

return
new ScaffoldedMigration(migration.MigrationId)
Expand Down Expand Up @@ -145,13 +145,15 @@ protected virtual string CreateMigrationId(string migrationName)

protected virtual void ScaffoldSnapshotModel(
[NotNull] IModel model,
[NotNull] Type contextType,
[NotNull] IndentedStringBuilder snapshotModelCode)
{
Check.NotNull(model, "model");
Check.NotNull(contextType, "contextType");

var className = GetClassName(model);

MigrationCodeGenerator.ModelCodeGenerator.GenerateModelSnapshotClass(MigrationNamespace, className, model, snapshotModelCode);
MigrationCodeGenerator.ModelCodeGenerator.GenerateModelSnapshotClass(MigrationNamespace, className, model, contextType, snapshotModelCode);
}

protected virtual string GetClassName([NotNull] IMigrationMetadata migration)
Expand Down
18 changes: 11 additions & 7 deletions src/EntityFramework.Migrations/Infrastructure/MigrationAssembly.cs
Expand Up @@ -36,11 +36,6 @@ public virtual Assembly Assembly
get { return ContextConfiguration.GetMigrationAssembly(); }
}

public virtual string Namespace
{
get { return ContextConfiguration.GetMigrationNamespace(); }
}

public virtual IReadOnlyList<IMigrationMetadata> Migrations
{
get { return _migrations ?? (_migrations = LoadMigrations()); }
Expand All @@ -53,29 +48,38 @@ public virtual IModel Model

protected virtual IReadOnlyList<IMigrationMetadata> LoadMigrations()
{
var contextType = ContextConfiguration.Context.GetType();
return Assembly.GetAccessibleTypes()
.Where(t => t.GetTypeInfo().IsSubclassOf(typeof(Migration))
&& t.GetPublicConstructor() != null
&& !t.GetTypeInfo().IsAbstract
&& !t.GetTypeInfo().IsGenericType
&& t.Namespace == Namespace)
&& TryGetContextType(t) == contextType)
.Select(t => (IMigrationMetadata)Activator.CreateInstance(t))
.OrderBy(m => m.MigrationId)
.ToArray();
}

protected virtual IModel LoadModel()
{
var contextType = ContextConfiguration.Context.GetType();
var modelSnapshotType = Assembly.GetAccessibleTypes().SingleOrDefault(
t => t.GetTypeInfo().IsSubclassOf(typeof(ModelSnapshot))
&& t.GetPublicConstructor() != null
&& !t.GetTypeInfo().IsAbstract
&& !t.GetTypeInfo().IsGenericType
&& t.Namespace == Namespace);
&& TryGetContextType(t) == contextType);

return modelSnapshotType != null
? ((ModelSnapshot)Activator.CreateInstance(modelSnapshotType)).Model
: null;
}

protected virtual Type TryGetContextType(Type type)
{
var contextTypeAttribute = type.GetTypeInfo().GetCustomAttribute<ContextTypeAttribute>(inherit: true);

return contextTypeAttribute != null ? contextTypeAttribute.ContextType : null;
}
}
}
14 changes: 4 additions & 10 deletions src/EntityFramework.Migrations/MigrationCodeGenerator.cs
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.Data.Entity.Migrations.Infrastructure;
using Microsoft.Data.Entity.Migrations.Model;
Expand Down Expand Up @@ -37,16 +38,9 @@ public virtual IReadOnlyList<string> GetMetadataNamespaces([NotNull] IMigrationM
{
Check.NotNull(migration, "migration");

var namespaces = new List<string>(GetMetadataDefaultNamespaces());

if (!string.IsNullOrEmpty(migration.ContextType.Namespace))
{
namespaces.Add(migration.ContextType.Namespace);
}

namespaces.AddRange(ModelCodeGenerator.GetNamespaces(migration.TargetModel));

return namespaces;
return GetMetadataDefaultNamespaces()
.Concat(ModelCodeGenerator.GetNamespaces(migration.TargetModel, migration.ContextType))
.ToList();
}

public virtual IReadOnlyList<string> GetDefaultNamespaces()
Expand Down
20 changes: 18 additions & 2 deletions src/EntityFramework.Migrations/ModelCodeGenerator.cs
@@ -1,18 +1,33 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 System.Linq;
using JetBrains.Annotations;
using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity.Migrations.Utilities;
using Microsoft.Data.Entity.Utilities;

namespace Microsoft.Data.Entity.Migrations
{
public abstract class ModelCodeGenerator
{
public virtual IReadOnlyList<string> GetNamespaces([NotNull] IModel model)
public virtual IReadOnlyList<string> GetNamespaces(
[NotNull] IModel model,
[NotNull] Type contextType)
{
return GetDefaultNamespaces();
Check.NotNull(model, "model");
Check.NotNull(contextType, "contextType");

var namespaces = GetDefaultNamespaces().ToList();

if (!string.IsNullOrEmpty(contextType.Namespace))
{
namespaces.Add(contextType.Namespace);
}

return namespaces;
}

public virtual IReadOnlyList<string> GetDefaultNamespaces()
Expand All @@ -33,6 +48,7 @@ public virtual IReadOnlyList<string> GetDefaultNamespaces()
[NotNull] string @namespace,
[NotNull] string className,
[NotNull] IModel model,
[NotNull] Type contextType,
[NotNull] IndentedStringBuilder stringBuilder);
}
}
Expand Up @@ -22,15 +22,7 @@ public static string GetMigrationNamespace([NotNull] this DbContextConfiguration
{
Check.NotNull(configuration, "configuration");

return RelationalOptionsExtension.Extract(configuration).MigrationNamespace
?? Combine(configuration.Context.GetType().Namespace, "Migrations");
}

private static string Combine(string namespace1, string namespace2)
{
return string.IsNullOrEmpty(namespace1)
? namespace2
: namespace1 + "." + namespace2;
return RelationalOptionsExtension.Extract(configuration).MigrationNamespace;
}
}
}
Expand Up @@ -572,15 +572,18 @@ public void Generate_model_snapshot_class()
model.AddEntityType(entityType);

var stringBuilder = new IndentedStringBuilder();
new CSharpModelCodeGenerator().GenerateModelSnapshotClass("MyNamespace", "MyClass", model, stringBuilder);
new CSharpModelCodeGenerator()
.GenerateModelSnapshotClass("MyNamespace", "MyClass", model, typeof(MyContext), stringBuilder);

Assert.Equal(
@"using Microsoft.Data.Entity.Metadata;
@"using Microsoft.Data.Entity.Commands.Tests.Migrations;
using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity.Migrations.Infrastructure;
using System;
namespace MyNamespace
{
[ContextType(typeof(CSharpModelCodeGeneratorTest.MyContext))]
public class MyClass : ModelSnapshot
{
public override IModel Model
Expand Down Expand Up @@ -621,5 +624,9 @@ private class Product
{
public int Id { get; set; }
}

public class MyContext : DbContext
{
}
}
}
Expand Up @@ -153,12 +153,14 @@ private static void ValidateEmptyModelSnapshot(string className, string modelSna
Assert.Equal("ContextModelSnapshot", className);

Assert.Equal(
@"using Microsoft.Data.Entity.Metadata;
@"using Microsoft.Data.Entity.Commands.Tests.Migrations;
using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity.Migrations.Infrastructure;
using System;
namespace MyNamespace
{
[ContextType(typeof(MigrationScaffolderTest.Context))]
public class ContextModelSnapshot : ModelSnapshot
{
public override IModel Model
Expand Down Expand Up @@ -251,12 +253,14 @@ private static void ValidateModelSnapshot(string className, string modelSnapshot
Assert.Equal("ContextModelSnapshot", className);

Assert.Equal(
@"using Microsoft.Data.Entity.Metadata;
@"using Microsoft.Data.Entity.Commands.Tests.Migrations;
using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity.Migrations.Infrastructure;
using System;
namespace MyNamespace
{
[ContextType(typeof(MigrationScaffolderTest.Context))]
public class ContextModelSnapshot : ModelSnapshot
{
public override IModel Model
Expand Down Expand Up @@ -408,12 +412,14 @@ private static void ValidateModelWithForeignKeysSnapshot(string className, strin
Assert.Equal("ContextModelSnapshot", className);

Assert.Equal(
@"using Microsoft.Data.Entity.Metadata;
@"using Microsoft.Data.Entity.Commands.Tests.Migrations;
using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity.Migrations.Infrastructure;
using System;
namespace MyNamespace
{
[ContextType(typeof(MigrationScaffolderTest.Context))]
public class ContextModelSnapshot : ModelSnapshot
{
public override IModel Model
Expand Down Expand Up @@ -600,12 +606,14 @@ private static void ValidateModelWithCompositeKeysSnapshot(string className, str
Assert.Equal("ContextModelSnapshot", className);

Assert.Equal(
@"using Microsoft.Data.Entity.Metadata;
@"using Microsoft.Data.Entity.Commands.Tests.Migrations;
using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity.Migrations.Infrastructure;
using System;
namespace MyNamespace
{
[ContextType(typeof(MigrationScaffolderTest.Context))]
public class ContextModelSnapshot : ModelSnapshot
{
public override IModel Model
Expand Down
Expand Up @@ -22,7 +22,6 @@ public void Create_migration_assembly()
var migrationAssembly = new MigrationAssembly(context.Configuration);

Assert.Equal("EntityFramework.Migrations.Tests", migrationAssembly.Assembly.GetName().Name);
Assert.Equal("Microsoft.Data.Entity.Migrations.Tests.Infrastructure.Migrations", migrationAssembly.Namespace);
}
}

Expand All @@ -39,7 +38,6 @@ public void Configure_assembly_and_namespace()
var migrationAssembly = new MigrationAssembly(context.Configuration);

Assert.Equal("MockAssembly", migrationAssembly.Assembly.FullName);
Assert.Equal("MyNamespace", migrationAssembly.Namespace);
}
}

Expand Down Expand Up @@ -121,6 +119,7 @@ public override string FullName

namespace Migrations
{
[ContextType(typeof(MigrationAssemblyTest.Context))]
public class Migration2 : Migration, IMigrationMetadata
{
public override void Up(MigrationBuilder migrationBuilder)
Expand All @@ -139,6 +138,7 @@ string IMigrationMetadata.MigrationId
}
}

[ContextType(typeof(MigrationAssemblyTest.Context))]
public class Migration1 : Migration, IMigrationMetadata
{
public override void Up(MigrationBuilder migrationBuilder)
Expand All @@ -157,6 +157,7 @@ string IMigrationMetadata.MigrationId
}
}

[ContextType(typeof(MigrationAssemblyTest.Context))]
public class ContextModelSnapshot : ModelSnapshot
{
public override IModel Model
Expand Down

0 comments on commit 5c6be5f

Please sign in to comment.