Skip to content

Commit e225db0

Browse files
committed
Added extension method for DbContextOptionsBuilder to remove conventions.
1 parent 0bb7571 commit e225db0

File tree

8 files changed

+463
-1
lines changed

8 files changed

+463
-1
lines changed

samples/Thinktecture.EntityFrameworkCore.SqlServer.Samples/SamplesContext.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
12
using Microsoft.Extensions.Configuration;
23
using Microsoft.Extensions.DependencyInjection;
34
using Microsoft.Extensions.Logging;
45
using Thinktecture.Database;
56
using Thinktecture.EntityFrameworkCore;
7+
using Thinktecture.EntityFrameworkCore.Conventions;
68

79
namespace Thinktecture;
810

@@ -53,6 +55,7 @@ public IServiceProvider CreateServiceProvider(string? schema = null)
5355
.AddCollectionParameterSupport()
5456
.UseThinktectureSqlServerMigrationsSqlGenerator();
5557
})
58+
.RemoveConvention(ConventionType.EntityTypePrimaryKeyChangedConventions, typeof(SqlServerValueGenerationConvention))
5659
.EnableSensitiveDataLogging()
5760
.UseLoggerFactory(_loggerFactory)
5861
.AddSchemaRespectingComponents()
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Microsoft.EntityFrameworkCore.Infrastructure;
2+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
3+
4+
namespace Thinktecture.EntityFrameworkCore.Conventions;
5+
6+
/// <summary>
7+
/// Convention not found in current <see cref="ConventionSet"/>.
8+
/// </summary>
9+
public class ConventionNotFoundException : Exception
10+
{
11+
internal ConventionNotFoundException(ConventionToRemove conventionToRemove)
12+
: base($"Could not remove the convention with the implementation type '{conventionToRemove.ImplementationTypeToRemove.ShortDisplayName()}' because it wasn't in the collection '{conventionToRemove.ConventionType.CollectionName}' of the current convention set.")
13+
{
14+
}
15+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
2+
3+
namespace Thinktecture.EntityFrameworkCore.Conventions;
4+
5+
internal record ConventionToRemove(ConventionType ConventionType, Type ImplementationTypeToRemove, bool ThrowIfNotFound)
6+
{
7+
public bool RemoveConvention(ConventionSet conventionSet)
8+
{
9+
return ConventionType.RemoveConvention(conventionSet, ImplementationTypeToRemove);
10+
}
11+
}
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
using Microsoft.EntityFrameworkCore.Infrastructure;
2+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
3+
4+
namespace Thinktecture.EntityFrameworkCore.Conventions;
5+
6+
/// <summary>
7+
/// A convention type.
8+
/// </summary>
9+
public abstract class ConventionType
10+
{
11+
/// <summary>
12+
/// Conventions to run to setup the initial model.
13+
/// </summary>
14+
public static readonly ConventionType ModelInitializedConventions = Create("ModelInitializedConventions", set => set.ModelInitializedConventions);
15+
16+
/// <summary>
17+
/// Conventions to run when model building is completed.
18+
/// </summary>
19+
public static readonly ConventionType ModelFinalizingConventions = Create("ModelFinalizingConventions", set => set.ModelFinalizingConventions);
20+
21+
/// <summary>
22+
/// Conventions to run when model validation is completed.
23+
/// </summary>
24+
public static readonly ConventionType ModelFinalizedConventions = Create("ModelFinalizedConventions", set => set.ModelFinalizedConventions);
25+
26+
/// <summary>
27+
/// Conventions to run when an annotation is set or removed on a model.
28+
/// </summary>
29+
public static readonly ConventionType ModelAnnotationChangedConventions = Create("ModelAnnotationChangedConventions", set => set.ModelAnnotationChangedConventions);
30+
31+
/// <summary>
32+
/// Conventions to run when an entity type is added to the model.
33+
/// </summary>
34+
public static readonly ConventionType EntityTypeAddedConventions = Create("EntityTypeAddedConventions", set => set.EntityTypeAddedConventions);
35+
36+
/// <summary>
37+
/// Conventions to run when an entity type is ignored.
38+
/// </summary>
39+
public static readonly ConventionType EntityTypeIgnoredConventions = Create("EntityTypeIgnoredConventions", set => set.EntityTypeIgnoredConventions);
40+
41+
/// <summary>
42+
/// Conventions to run when an entity type is removed.
43+
/// </summary>
44+
public static readonly ConventionType EntityTypeRemovedConventions = Create("EntityTypeRemovedConventions", set => set.EntityTypeRemovedConventions);
45+
46+
/// <summary>
47+
/// Conventions to run when a property is ignored.
48+
/// </summary>
49+
public static readonly ConventionType EntityTypeMemberIgnoredConventions = Create("EntityTypeMemberIgnoredConventions", set => set.EntityTypeMemberIgnoredConventions);
50+
51+
/// <summary>
52+
/// Conventions to run when the base entity type is changed.
53+
/// </summary>
54+
public static readonly ConventionType EntityTypeBaseTypeChangedConventions = Create("EntityTypeBaseTypeChangedConventions", set => set.EntityTypeBaseTypeChangedConventions);
55+
56+
/// <summary>
57+
/// Conventions to run when a primary key is changed.
58+
/// </summary>
59+
public static readonly ConventionType EntityTypePrimaryKeyChangedConventions = Create("EntityTypePrimaryKeyChangedConventions", set => set.EntityTypePrimaryKeyChangedConventions);
60+
61+
/// <summary>
62+
/// Conventions to run when an annotation is set or removed on an entity type.
63+
/// </summary>
64+
public static readonly ConventionType EntityTypeAnnotationChangedConventions = Create("EntityTypeAnnotationChangedConventions", set => set.EntityTypeAnnotationChangedConventions);
65+
66+
/// <summary>
67+
/// Conventions to run when a foreign key is added.
68+
/// </summary>
69+
public static readonly ConventionType ForeignKeyAddedConventions = Create("ForeignKeyAddedConventions", set => set.ForeignKeyAddedConventions);
70+
71+
/// <summary>
72+
/// Conventions to run when a foreign key is removed.
73+
/// </summary>
74+
public static readonly ConventionType ForeignKeyRemovedConventions = Create("ForeignKeyRemovedConventions", set => set.ForeignKeyRemovedConventions);
75+
76+
/// <summary>
77+
/// Conventions to run when the principal end of a relationship is configured.
78+
/// </summary>
79+
public static readonly ConventionType ForeignKeyPrincipalEndChangedConventions = Create("ForeignKeyPrincipalEndChangedConventions", set => set.ForeignKeyPrincipalEndChangedConventions);
80+
81+
/// <summary>
82+
/// Conventions to run when the properties or the principal key of a foreign key are changed.
83+
/// </summary>
84+
public static readonly ConventionType ForeignKeyPropertiesChangedConventions = Create("ForeignKeyPropertiesChangedConventions", set => set.ForeignKeyPropertiesChangedConventions);
85+
86+
/// <summary>
87+
/// Conventions to run when the uniqueness of a foreign key is changed.
88+
/// </summary>
89+
public static readonly ConventionType ForeignKeyUniquenessChangedConventions = Create("ForeignKeyUniquenessChangedConventions", set => set.ForeignKeyUniquenessChangedConventions);
90+
91+
/// <summary>
92+
/// Conventions to run when the requiredness of a foreign key is changed.
93+
/// </summary>
94+
public static readonly ConventionType ForeignKeyRequirednessChangedConventions = Create("ForeignKeyRequirednessChangedConventions", set => set.ForeignKeyRequirednessChangedConventions);
95+
96+
/// <summary>
97+
/// Conventions to run when the requiredness of a foreign key is changed.
98+
/// </summary>
99+
public static readonly ConventionType ForeignKeyDependentRequirednessChangedConventions = Create("ForeignKeyDependentRequirednessChangedConventions", set => set.ForeignKeyDependentRequirednessChangedConventions);
100+
101+
/// <summary>
102+
/// Conventions to run when the ownership of a foreign key is changed.
103+
/// </summary>
104+
public static readonly ConventionType ForeignKeyOwnershipChangedConventions = Create("ForeignKeyOwnershipChangedConventions", set => set.ForeignKeyOwnershipChangedConventions);
105+
106+
/// <summary>
107+
/// Conventions to run when an annotation is changed on a foreign key.
108+
/// </summary>
109+
public static readonly ConventionType ForeignKeyAnnotationChangedConventions = Create("ForeignKeyAnnotationChangedConventions", set => set.ForeignKeyAnnotationChangedConventions);
110+
111+
/// <summary>
112+
/// Conventions to run when a navigation is set to <see langword="null" /> on a foreign key.
113+
/// </summary>
114+
public static readonly ConventionType ForeignKeyNullNavigationSetConventions = Create("ForeignKeyNullNavigationSetConventions", set => set.ForeignKeyNullNavigationSetConventions);
115+
116+
/// <summary>
117+
/// Conventions to run when a navigation property is added.
118+
/// </summary>
119+
public static readonly ConventionType NavigationAddedConventions = Create("NavigationAddedConventions", set => set.NavigationAddedConventions);
120+
121+
/// <summary>
122+
/// Conventions to run when an annotation is changed on a navigation property.
123+
/// </summary>
124+
public static readonly ConventionType NavigationAnnotationChangedConventions = Create("NavigationAnnotationChangedConventions", set => set.NavigationAnnotationChangedConventions);
125+
126+
/// <summary>
127+
/// Conventions to run when a navigation property is removed.
128+
/// </summary>
129+
public static readonly ConventionType NavigationRemovedConventions = Create("NavigationRemovedConventions", set => set.NavigationRemovedConventions);
130+
131+
/// <summary>
132+
/// Conventions to run when a skip navigation property is added.
133+
/// </summary>
134+
public static readonly ConventionType SkipNavigationAddedConventions = Create("SkipNavigationAddedConventions", set => set.SkipNavigationAddedConventions);
135+
136+
/// <summary>
137+
/// Conventions to run when an annotation is changed on a skip navigation property.
138+
/// </summary>
139+
public static readonly ConventionType SkipNavigationAnnotationChangedConventions = Create("SkipNavigationAnnotationChangedConventions", set => set.SkipNavigationAnnotationChangedConventions);
140+
141+
/// <summary>
142+
/// Conventions to run when a skip navigation foreign key is changed.
143+
/// </summary>
144+
public static readonly ConventionType SkipNavigationForeignKeyChangedConventions = Create("SkipNavigationForeignKeyChangedConventions", set => set.SkipNavigationForeignKeyChangedConventions);
145+
146+
/// <summary>
147+
/// Conventions to run when a skip navigation inverse is changed.
148+
/// </summary>
149+
public static readonly ConventionType SkipNavigationInverseChangedConventions = Create("SkipNavigationInverseChangedConventions", set => set.SkipNavigationInverseChangedConventions);
150+
151+
/// <summary>
152+
/// Conventions to run when a skip navigation property is removed.
153+
/// </summary>
154+
public static readonly ConventionType SkipNavigationRemovedConventions = Create("SkipNavigationRemovedConventions", set => set.SkipNavigationRemovedConventions);
155+
156+
/// <summary>
157+
/// Conventions to run when a key is added.
158+
/// </summary>
159+
public static readonly ConventionType KeyAddedConventions = Create("KeyAddedConventions", set => set.KeyAddedConventions);
160+
161+
/// <summary>
162+
/// Conventions to run when a key is removed.
163+
/// </summary>
164+
public static readonly ConventionType KeyRemovedConventions = Create("KeyRemovedConventions", set => set.KeyRemovedConventions);
165+
166+
/// <summary>
167+
/// Conventions to run when an annotation is changed on a key.
168+
/// </summary>
169+
public static readonly ConventionType KeyAnnotationChangedConventions = Create("KeyAnnotationChangedConventions", set => set.KeyAnnotationChangedConventions);
170+
171+
/// <summary>
172+
/// Conventions to run when an index is added.
173+
/// </summary>
174+
public static readonly ConventionType IndexAddedConventions = Create("IndexAddedConventions", set => set.IndexAddedConventions);
175+
176+
/// <summary>
177+
/// Conventions to run when an index is removed.
178+
/// </summary>
179+
public static readonly ConventionType IndexRemovedConventions = Create("IndexRemovedConventions", set => set.IndexRemovedConventions);
180+
181+
/// <summary>
182+
/// Conventions to run when the uniqueness of an index is changed.
183+
/// </summary>
184+
public static readonly ConventionType IndexUniquenessChangedConventions = Create("IndexUniquenessChangedConventions", set => set.IndexUniquenessChangedConventions);
185+
186+
/// <summary>
187+
/// Conventions to run when an annotation is changed on an index.
188+
/// </summary>
189+
public static readonly ConventionType IndexAnnotationChangedConventions = Create("IndexAnnotationChangedConventions", set => set.IndexAnnotationChangedConventions);
190+
191+
/// <summary>
192+
/// Conventions to run when a property is added.
193+
/// </summary>
194+
public static readonly ConventionType PropertyAddedConventions = Create("PropertyAddedConventions", set => set.PropertyAddedConventions);
195+
196+
/// <summary>
197+
/// Conventions to run when the nullability of a property is changed.
198+
/// </summary>
199+
public static readonly ConventionType PropertyNullabilityChangedConventions = Create("PropertyNullabilityChangedConventions", set => set.PropertyNullabilityChangedConventions);
200+
201+
/// <summary>
202+
/// Conventions to run when the field of a property is changed.
203+
/// </summary>
204+
public static readonly ConventionType PropertyFieldChangedConventions = Create("PropertyFieldChangedConventions", set => set.PropertyFieldChangedConventions);
205+
206+
/// <summary>
207+
/// Conventions to run when an annotation is changed on a property.
208+
/// </summary>
209+
public static readonly ConventionType PropertyAnnotationChangedConventions = Create("PropertyAnnotationChangedConventions", set => set.PropertyAnnotationChangedConventions);
210+
211+
/// <summary>
212+
/// Conventions to run when a property is removed.
213+
/// </summary>
214+
public static readonly ConventionType PropertyRemovedConventions = Create("PropertyRemovedConventions", set => set.PropertyRemovedConventions);
215+
216+
/// <summary>
217+
/// The name collection the conventions of this type reside in <see cref="ConventionSet"/>.
218+
/// </summary>
219+
public string CollectionName { get; }
220+
221+
/// <summary>
222+
/// The type of the interface.
223+
/// </summary>
224+
public Type InterfaceType { get; }
225+
226+
private ConventionType(string collectionName, Type interfaceType)
227+
{
228+
CollectionName = collectionName ?? throw new ArgumentNullException(nameof(collectionName));
229+
InterfaceType = interfaceType ?? throw new ArgumentNullException(nameof(interfaceType));
230+
}
231+
232+
/// <inheritdoc />
233+
public override string ToString()
234+
{
235+
return InterfaceType.ShortDisplayName();
236+
}
237+
238+
/// <summary>
239+
/// Removes the <paramref name="conventionToRemove"/> from the provided <paramref name="conventionSet"/>.
240+
/// </summary>
241+
/// <param name="conventionSet">Convention set to remove the <paramref name="conventionToRemove"/> from.</param>
242+
/// <param name="conventionToRemove">Implementation type of the convention to remove.</param>
243+
/// <returns><c>true</c> if the <paramref name="conventionToRemove"/> is found and removed from <paramref name="conventionSet"/>; otherwise <c>false</c>.</returns>
244+
public abstract bool RemoveConvention(ConventionSet conventionSet, Type conventionToRemove);
245+
246+
private static GenericConventionType<TConvention> Create<TConvention>(string name, Func<ConventionSet, IList<TConvention>> conventionSelector)
247+
{
248+
return new GenericConventionType<TConvention>(name, conventionSelector);
249+
}
250+
251+
private class GenericConventionType<TConvention> : ConventionType
252+
{
253+
private readonly Func<ConventionSet, IList<TConvention>> _conventionSelector;
254+
255+
public GenericConventionType(string collectionName, Func<ConventionSet, IList<TConvention>> conventionSelector)
256+
: base(collectionName, typeof(TConvention))
257+
{
258+
_conventionSelector = conventionSelector;
259+
}
260+
261+
public override bool RemoveConvention(ConventionSet conventionSet, Type conventionToRemove)
262+
{
263+
return ConventionSet.Remove(_conventionSelector(conventionSet), conventionToRemove);
264+
}
265+
}
266+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
2+
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
3+
using Thinktecture.EntityFrameworkCore.Infrastructure;
4+
5+
namespace Thinktecture.EntityFrameworkCore.Conventions;
6+
7+
internal class RelationalConventionSetPlugin : IConventionSetPlugin
8+
{
9+
private readonly RelationalDbContextOptionsExtensionOptions _options;
10+
11+
public RelationalConventionSetPlugin(RelationalDbContextOptionsExtensionOptions options)
12+
{
13+
_options = options;
14+
}
15+
16+
public ConventionSet ModifyConventions(ConventionSet conventionSet)
17+
{
18+
foreach (var conventionToRemove in _options.ConventionsToRemove)
19+
{
20+
var successful = conventionToRemove.RemoveConvention(conventionSet);
21+
22+
if (!successful && conventionToRemove.ThrowIfNotFound)
23+
throw new ConventionNotFoundException(conventionToRemove);
24+
}
25+
26+
return conventionSet;
27+
}
28+
}

0 commit comments

Comments
 (0)