Skip to content

Commit 5c6be5f

Browse files
committed
Use ContextTypeAttribute during migration discovery
1 parent 14deb62 commit 5c6be5f

File tree

9 files changed

+68
-39
lines changed

9 files changed

+68
-39
lines changed

src/EntityFramework.Commands/Migrations/CSharpModelCodeGenerator.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.Linq;
67
using JetBrains.Annotations;
@@ -22,6 +23,7 @@ public override void GenerateModelSnapshotClass(
2223
string @namespace,
2324
string className,
2425
IModel model,
26+
Type contextType,
2527
IndentedStringBuilder stringBuilder)
2628
{
2729
Check.NotEmpty(className, "className");
@@ -30,7 +32,7 @@ public override void GenerateModelSnapshotClass(
3032
Check.NotNull(stringBuilder, "stringBuilder");
3133

3234
// TODO: Consider namespace ordering, for example putting System namespaces first
33-
foreach (var ns in GetNamespaces(model).OrderBy(n => n).Distinct())
35+
foreach (var ns in GetNamespaces(model, contextType).OrderBy(n => n).Distinct())
3436
{
3537
stringBuilder
3638
.Append("using ")
@@ -47,6 +49,9 @@ public override void GenerateModelSnapshotClass(
4749
using (stringBuilder.Indent())
4850
{
4951
stringBuilder
52+
.Append("[ContextType(typeof(")
53+
.Append(contextType.GetNestedName())
54+
.AppendLine("))]")
5055
.Append("public class ")
5156
.Append(className)
5257
.AppendLine(" : ModelSnapshot")

src/EntityFramework.Commands/Migrations/MigrationScaffolder.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public virtual ScaffoldedMigration ScaffoldMigration([NotNull] string migrationN
8181
var snapshotModelCode = new IndentedStringBuilder();
8282

8383
ScaffoldMigration(migration, migrationCode, migrationMetadataCode);
84-
ScaffoldSnapshotModel(migration.TargetModel, snapshotModelCode);
84+
ScaffoldSnapshotModel(migration.TargetModel, migration.ContextType, snapshotModelCode);
8585

8686
return
8787
new ScaffoldedMigration(migration.MigrationId)
@@ -145,13 +145,15 @@ protected virtual void ScaffoldMigration(
145145

146146
protected virtual void ScaffoldSnapshotModel(
147147
[NotNull] IModel model,
148+
[NotNull] Type contextType,
148149
[NotNull] IndentedStringBuilder snapshotModelCode)
149150
{
150151
Check.NotNull(model, "model");
152+
Check.NotNull(contextType, "contextType");
151153

152154
var className = GetClassName(model);
153155

154-
MigrationCodeGenerator.ModelCodeGenerator.GenerateModelSnapshotClass(MigrationNamespace, className, model, snapshotModelCode);
156+
MigrationCodeGenerator.ModelCodeGenerator.GenerateModelSnapshotClass(MigrationNamespace, className, model, contextType, snapshotModelCode);
155157
}
156158

157159
protected virtual string GetClassName([NotNull] IMigrationMetadata migration)

src/EntityFramework.Migrations/Infrastructure/MigrationAssembly.cs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@ public virtual Assembly Assembly
3636
get { return ContextConfiguration.GetMigrationAssembly(); }
3737
}
3838

39-
public virtual string Namespace
40-
{
41-
get { return ContextConfiguration.GetMigrationNamespace(); }
42-
}
43-
4439
public virtual IReadOnlyList<IMigrationMetadata> Migrations
4540
{
4641
get { return _migrations ?? (_migrations = LoadMigrations()); }
@@ -53,29 +48,38 @@ public virtual IModel Model
5348

5449
protected virtual IReadOnlyList<IMigrationMetadata> LoadMigrations()
5550
{
51+
var contextType = ContextConfiguration.Context.GetType();
5652
return Assembly.GetAccessibleTypes()
5753
.Where(t => t.GetTypeInfo().IsSubclassOf(typeof(Migration))
5854
&& t.GetPublicConstructor() != null
5955
&& !t.GetTypeInfo().IsAbstract
6056
&& !t.GetTypeInfo().IsGenericType
61-
&& t.Namespace == Namespace)
57+
&& TryGetContextType(t) == contextType)
6258
.Select(t => (IMigrationMetadata)Activator.CreateInstance(t))
6359
.OrderBy(m => m.MigrationId)
6460
.ToArray();
6561
}
6662

6763
protected virtual IModel LoadModel()
6864
{
65+
var contextType = ContextConfiguration.Context.GetType();
6966
var modelSnapshotType = Assembly.GetAccessibleTypes().SingleOrDefault(
7067
t => t.GetTypeInfo().IsSubclassOf(typeof(ModelSnapshot))
7168
&& t.GetPublicConstructor() != null
7269
&& !t.GetTypeInfo().IsAbstract
7370
&& !t.GetTypeInfo().IsGenericType
74-
&& t.Namespace == Namespace);
71+
&& TryGetContextType(t) == contextType);
7572

7673
return modelSnapshotType != null
7774
? ((ModelSnapshot)Activator.CreateInstance(modelSnapshotType)).Model
7875
: null;
7976
}
77+
78+
protected virtual Type TryGetContextType(Type type)
79+
{
80+
var contextTypeAttribute = type.GetTypeInfo().GetCustomAttribute<ContextTypeAttribute>(inherit: true);
81+
82+
return contextTypeAttribute != null ? contextTypeAttribute.ContextType : null;
83+
}
8084
}
8185
}

src/EntityFramework.Migrations/MigrationCodeGenerator.cs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.Collections.Generic;
5+
using System.Linq;
56
using JetBrains.Annotations;
67
using Microsoft.Data.Entity.Migrations.Infrastructure;
78
using Microsoft.Data.Entity.Migrations.Model;
@@ -37,16 +38,9 @@ public virtual IReadOnlyList<string> GetMetadataNamespaces([NotNull] IMigrationM
3738
{
3839
Check.NotNull(migration, "migration");
3940

40-
var namespaces = new List<string>(GetMetadataDefaultNamespaces());
41-
42-
if (!string.IsNullOrEmpty(migration.ContextType.Namespace))
43-
{
44-
namespaces.Add(migration.ContextType.Namespace);
45-
}
46-
47-
namespaces.AddRange(ModelCodeGenerator.GetNamespaces(migration.TargetModel));
48-
49-
return namespaces;
41+
return GetMetadataDefaultNamespaces()
42+
.Concat(ModelCodeGenerator.GetNamespaces(migration.TargetModel, migration.ContextType))
43+
.ToList();
5044
}
5145

5246
public virtual IReadOnlyList<string> GetDefaultNamespaces()

src/EntityFramework.Migrations/ModelCodeGenerator.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
45
using System.Collections.Generic;
6+
using System.Linq;
57
using JetBrains.Annotations;
68
using Microsoft.Data.Entity.Metadata;
9+
using Microsoft.Data.Entity.Migrations.Utilities;
710
using Microsoft.Data.Entity.Utilities;
811

912
namespace Microsoft.Data.Entity.Migrations
1013
{
1114
public abstract class ModelCodeGenerator
1215
{
13-
public virtual IReadOnlyList<string> GetNamespaces([NotNull] IModel model)
16+
public virtual IReadOnlyList<string> GetNamespaces(
17+
[NotNull] IModel model,
18+
[NotNull] Type contextType)
1419
{
15-
return GetDefaultNamespaces();
20+
Check.NotNull(model, "model");
21+
Check.NotNull(contextType, "contextType");
22+
23+
var namespaces = GetDefaultNamespaces().ToList();
24+
25+
if (!string.IsNullOrEmpty(contextType.Namespace))
26+
{
27+
namespaces.Add(contextType.Namespace);
28+
}
29+
30+
return namespaces;
1631
}
1732

1833
public virtual IReadOnlyList<string> GetDefaultNamespaces()
@@ -33,6 +48,7 @@ public abstract void GenerateModelSnapshotClass(
3348
[NotNull] string @namespace,
3449
[NotNull] string className,
3550
[NotNull] IModel model,
51+
[NotNull] Type contextType,
3652
[NotNull] IndentedStringBuilder stringBuilder);
3753
}
3854
}

src/EntityFramework.Migrations/Utilities/DbContextConfigurationExtensions.cs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,7 @@ public static string GetMigrationNamespace([NotNull] this DbContextConfiguration
2222
{
2323
Check.NotNull(configuration, "configuration");
2424

25-
return RelationalOptionsExtension.Extract(configuration).MigrationNamespace
26-
?? Combine(configuration.Context.GetType().Namespace, "Migrations");
27-
}
28-
29-
private static string Combine(string namespace1, string namespace2)
30-
{
31-
return string.IsNullOrEmpty(namespace1)
32-
? namespace2
33-
: namespace1 + "." + namespace2;
25+
return RelationalOptionsExtension.Extract(configuration).MigrationNamespace;
3426
}
3527
}
3628
}

test/EntityFramework.Commands.Tests/Migrations/CSharpModelCodeGeneratorTest.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,15 +572,18 @@ public void Generate_model_snapshot_class()
572572
model.AddEntityType(entityType);
573573

574574
var stringBuilder = new IndentedStringBuilder();
575-
new CSharpModelCodeGenerator().GenerateModelSnapshotClass("MyNamespace", "MyClass", model, stringBuilder);
575+
new CSharpModelCodeGenerator()
576+
.GenerateModelSnapshotClass("MyNamespace", "MyClass", model, typeof(MyContext), stringBuilder);
576577

577578
Assert.Equal(
578-
@"using Microsoft.Data.Entity.Metadata;
579+
@"using Microsoft.Data.Entity.Commands.Tests.Migrations;
580+
using Microsoft.Data.Entity.Metadata;
579581
using Microsoft.Data.Entity.Migrations.Infrastructure;
580582
using System;
581583
582584
namespace MyNamespace
583585
{
586+
[ContextType(typeof(CSharpModelCodeGeneratorTest.MyContext))]
584587
public class MyClass : ModelSnapshot
585588
{
586589
public override IModel Model
@@ -621,5 +624,9 @@ private class Product
621624
{
622625
public int Id { get; set; }
623626
}
627+
628+
public class MyContext : DbContext
629+
{
630+
}
624631
}
625632
}

test/EntityFramework.Commands.Tests/Migrations/MigrationScaffolderTest.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,14 @@ private static void ValidateEmptyModelSnapshot(string className, string modelSna
153153
Assert.Equal("ContextModelSnapshot", className);
154154

155155
Assert.Equal(
156-
@"using Microsoft.Data.Entity.Metadata;
156+
@"using Microsoft.Data.Entity.Commands.Tests.Migrations;
157+
using Microsoft.Data.Entity.Metadata;
157158
using Microsoft.Data.Entity.Migrations.Infrastructure;
158159
using System;
159160
160161
namespace MyNamespace
161162
{
163+
[ContextType(typeof(MigrationScaffolderTest.Context))]
162164
public class ContextModelSnapshot : ModelSnapshot
163165
{
164166
public override IModel Model
@@ -251,12 +253,14 @@ private static void ValidateModelSnapshot(string className, string modelSnapshot
251253
Assert.Equal("ContextModelSnapshot", className);
252254

253255
Assert.Equal(
254-
@"using Microsoft.Data.Entity.Metadata;
256+
@"using Microsoft.Data.Entity.Commands.Tests.Migrations;
257+
using Microsoft.Data.Entity.Metadata;
255258
using Microsoft.Data.Entity.Migrations.Infrastructure;
256259
using System;
257260
258261
namespace MyNamespace
259262
{
263+
[ContextType(typeof(MigrationScaffolderTest.Context))]
260264
public class ContextModelSnapshot : ModelSnapshot
261265
{
262266
public override IModel Model
@@ -408,12 +412,14 @@ private static void ValidateModelWithForeignKeysSnapshot(string className, strin
408412
Assert.Equal("ContextModelSnapshot", className);
409413

410414
Assert.Equal(
411-
@"using Microsoft.Data.Entity.Metadata;
415+
@"using Microsoft.Data.Entity.Commands.Tests.Migrations;
416+
using Microsoft.Data.Entity.Metadata;
412417
using Microsoft.Data.Entity.Migrations.Infrastructure;
413418
using System;
414419
415420
namespace MyNamespace
416421
{
422+
[ContextType(typeof(MigrationScaffolderTest.Context))]
417423
public class ContextModelSnapshot : ModelSnapshot
418424
{
419425
public override IModel Model
@@ -600,12 +606,14 @@ private static void ValidateModelWithCompositeKeysSnapshot(string className, str
600606
Assert.Equal("ContextModelSnapshot", className);
601607

602608
Assert.Equal(
603-
@"using Microsoft.Data.Entity.Metadata;
609+
@"using Microsoft.Data.Entity.Commands.Tests.Migrations;
610+
using Microsoft.Data.Entity.Metadata;
604611
using Microsoft.Data.Entity.Migrations.Infrastructure;
605612
using System;
606613
607614
namespace MyNamespace
608615
{
616+
[ContextType(typeof(MigrationScaffolderTest.Context))]
609617
public class ContextModelSnapshot : ModelSnapshot
610618
{
611619
public override IModel Model

test/EntityFramework.Migrations.Tests/Infrastructure/MigrationAssemblyTest.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ public void Create_migration_assembly()
2222
var migrationAssembly = new MigrationAssembly(context.Configuration);
2323

2424
Assert.Equal("EntityFramework.Migrations.Tests", migrationAssembly.Assembly.GetName().Name);
25-
Assert.Equal("Microsoft.Data.Entity.Migrations.Tests.Infrastructure.Migrations", migrationAssembly.Namespace);
2625
}
2726
}
2827

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

4140
Assert.Equal("MockAssembly", migrationAssembly.Assembly.FullName);
42-
Assert.Equal("MyNamespace", migrationAssembly.Namespace);
4341
}
4442
}
4543

@@ -121,6 +119,7 @@ public override string FullName
121119

122120
namespace Migrations
123121
{
122+
[ContextType(typeof(MigrationAssemblyTest.Context))]
124123
public class Migration2 : Migration, IMigrationMetadata
125124
{
126125
public override void Up(MigrationBuilder migrationBuilder)
@@ -139,6 +138,7 @@ string IMigrationMetadata.MigrationId
139138
}
140139
}
141140

141+
[ContextType(typeof(MigrationAssemblyTest.Context))]
142142
public class Migration1 : Migration, IMigrationMetadata
143143
{
144144
public override void Up(MigrationBuilder migrationBuilder)
@@ -157,6 +157,7 @@ string IMigrationMetadata.MigrationId
157157
}
158158
}
159159

160+
[ContextType(typeof(MigrationAssemblyTest.Context))]
160161
public class ContextModelSnapshot : ModelSnapshot
161162
{
162163
public override IModel Model

0 commit comments

Comments
 (0)