Skip to content

Commit

Permalink
Change default embedded discriminator property from "Discriminator" t…
Browse files Browse the repository at this point in the history
…o "$type"

Fixes #34269

Use the following to revert back to the old behavior:

```C#
modelBuilder.HasEmbeddedDiscriminatorName("Discriminator");
```
  • Loading branch information
ajcvickers committed Aug 2, 2024
1 parent e667bf8 commit 181cf1b
Show file tree
Hide file tree
Showing 51 changed files with 1,657 additions and 1,616 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore.Metadata.Conventions;
Expand All @@ -19,7 +18,8 @@ public class CosmosDiscriminatorConvention :
IForeignKeyOwnershipChangedConvention,
IForeignKeyRemovedConvention,
IEntityTypeAddedConvention,
IEntityTypeAnnotationChangedConvention
IEntityTypeAnnotationChangedConvention,
IModelEmbeddedDiscriminatorNameConvention
{
/// <summary>
/// Creates a new instance of <see cref="CosmosDiscriminatorConvention" />.
Expand Down Expand Up @@ -86,7 +86,7 @@ private static void ProcessEntityType(IConventionEntityTypeBuilder entityTypeBui

if (entityType.IsDocumentRoot())
{
entityTypeBuilder.HasDiscriminator(typeof(string))
entityTypeBuilder.HasDiscriminator(entityType.Model.GetEmbeddedDiscriminatorName(), typeof(string))
?.HasValue(entityType, entityType.ShortName());
}
else
Expand Down Expand Up @@ -125,7 +125,7 @@ public override void ProcessEntityTypeBaseTypeChanged(
{
if (entityType.IsDocumentRoot())
{
entityTypeBuilder.HasDiscriminator(typeof(string));
entityTypeBuilder.HasDiscriminator(entityType.Model.GetEmbeddedDiscriminatorName(), typeof(string));
}
}
else
Expand All @@ -137,7 +137,7 @@ public override void ProcessEntityTypeBaseTypeChanged(
return;
}

var discriminator = rootType.Builder.HasDiscriminator(typeof(string));
var discriminator = rootType.Builder.HasDiscriminator(entityType.Model.GetEmbeddedDiscriminatorName(), typeof(string));
if (discriminator != null)
{
SetDefaultDiscriminatorValues(entityTypeBuilder.Metadata.GetDerivedTypesInclusive(), discriminator);
Expand All @@ -163,4 +163,19 @@ public override void ProcessEntityTypeRemoved(
IConventionContext<IConventionEntityType> context)
{
}

/// <inheritdoc/>
public void ProcessEmbeddedDiscriminatorName(
IConventionModelBuilder modelBuilder, string? oldName, string? newName, IConventionContext<string> context)
{
if (oldName == newName)
{
return;
}

foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
{
ProcessEntityType(entityType.Builder);
}
}
}
16 changes: 16 additions & 0 deletions src/EFCore/Metadata/Builders/IConventionModelBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -341,4 +341,20 @@ bool CanHaveSharedTypeEntity(
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns><see langword="true" /> if the given property access mode can be set.</returns>
bool CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);

/// <summary>
/// Sets the name to use for discriminator properties embedded in JSON documents. The default is "$type".
/// </summary>
/// <param name="name">The property name, or <see langword="null" /> to clear the name set.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>The same builder instance if the configuration was successful, <see langword="null" /> otherwise.</returns>
IConventionModelBuilder? HasEmbeddedDiscriminatorName(string? name, bool fromDataAnnotation = false);

/// <summary>
/// Returns a value indicating whether the given name can be set from the current configuration source
/// </summary>
/// <param name="name">The property name, or <see langword="null" /> to clear the name set.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns><see langword="true" /> if the given property access mode can be set.</returns>
bool CanSetEmbeddedDiscriminatorName(string? name, bool fromDataAnnotation = false);
}
21 changes: 21 additions & 0 deletions src/EFCore/Metadata/Conventions/ConventionSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public class ConventionSet
/// </summary>
public virtual List<IModelAnnotationChangedConvention> ModelAnnotationChangedConventions { get; } = [];

/// <summary>
/// Conventions to run when an annotation is set or removed on an entity type.
/// </summary>
public virtual List<IModelEmbeddedDiscriminatorNameConvention> ModelEmbeddedDiscriminatorNameConventions { get; } = [];

/// <summary>
/// Conventions to run when a type is ignored.
/// </summary>
Expand Down Expand Up @@ -321,6 +326,12 @@ public virtual void Replace<TImplementation>(TImplementation newConvention)
ModelAnnotationChangedConventions.Add(modelAnnotationChangedConvention);
}

if (newConvention is IModelEmbeddedDiscriminatorNameConvention modelEmbeddedDiscriminatorNameConvention
&& !Replace(ModelEmbeddedDiscriminatorNameConventions, modelEmbeddedDiscriminatorNameConvention, oldConventionType))
{
ModelEmbeddedDiscriminatorNameConventions.Add(modelEmbeddedDiscriminatorNameConvention);
}

if (newConvention is ITypeIgnoredConvention typeIgnoredConvention
&& !Replace(TypeIgnoredConventions, typeIgnoredConvention, oldConventionType))
{
Expand Down Expand Up @@ -696,6 +707,11 @@ public virtual void Add(IConvention convention)
ModelAnnotationChangedConventions.Add(modelAnnotationChangedConvention);
}

if (convention is IModelEmbeddedDiscriminatorNameConvention modelEmbeddedDiscriminatorNameConvention)
{
ModelEmbeddedDiscriminatorNameConventions.Add(modelEmbeddedDiscriminatorNameConvention);
}

if (convention is ITypeIgnoredConvention typeIgnoredConvention)
{
TypeIgnoredConventions.Add(typeIgnoredConvention);
Expand Down Expand Up @@ -1034,6 +1050,11 @@ public virtual void Remove(Type conventionType)
Remove(ModelAnnotationChangedConventions, conventionType);
}

if (typeof(IModelEmbeddedDiscriminatorNameConvention).IsAssignableFrom(conventionType))
{
Remove(ModelEmbeddedDiscriminatorNameConventions, conventionType);
}

if (typeof(ITypeIgnoredConvention).IsAssignableFrom(conventionType))
{
Remove(TypeIgnoredConventions, conventionType);
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/Metadata/Conventions/DiscriminatorConvention.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public virtual void ProcessDiscriminatorPropertySet(
return;
}

var discriminator = entityTypeBuilder.HasDiscriminator(typeof(string));
var discriminator = entityTypeBuilder.HasDiscriminator(name, typeof(string));
if (discriminator != null)
{
SetDefaultDiscriminatorValues(entityTypeBuilder.Metadata.GetDerivedTypesInclusive(), discriminator);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore.Metadata.Conventions;

/// <summary>
/// Represents an operation that should be performed when the embedded discriminator name for the model changes.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-conventions">Model building conventions</see> for more information and examples.
/// </remarks>
public interface IModelEmbeddedDiscriminatorNameConvention : IConvention
{
/// <summary>
/// Called after <see cref="ModelBuilder.HasEmbeddedDiscriminatorName"/> has been called.
/// </summary>
/// <param name="modelBuilder">The builder for the model.</param>
/// <param name="oldName">The current discriminator name.</param>
/// <param name="newName">The new discriminator name.</param>
/// <param name="context">Additional information associated with convention execution.</param>
void ProcessEmbeddedDiscriminatorName(
IConventionModelBuilder modelBuilder,
string? oldName,
string? newName,
IConventionContext<string> context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ public int GetLeafCount()
IConventionAnnotation? annotation,
IConventionAnnotation? oldAnnotation);

public abstract string? OnModelEmbeddedDiscriminatorNameChanged(
IConventionModelBuilder modelBuilder,
string? oldName,
string? newName);

public abstract IConventionNavigationBuilder? OnNavigationAdded(IConventionNavigationBuilder navigationBuilder);

public abstract string? OnNavigationRemoved(
Expand Down
Loading

0 comments on commit 181cf1b

Please sign in to comment.