Skip to content

Commit

Permalink
Add back some methods to the compiled model that are used for customi…
Browse files Browse the repository at this point in the history
…zation (#32805)

Fixes #32739
  • Loading branch information
AndriySvyryd authored Jan 16, 2024
1 parent 59816c3 commit 4211953
Show file tree
Hide file tree
Showing 16 changed files with 815 additions and 26 deletions.
19 changes: 12 additions & 7 deletions src/EFCore.Relational/Metadata/Internal/RelationalModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ private static void AddTables(

Check.DebugAssert(entityType.FindRuntimeAnnotationValue(RelationalAnnotationNames.TableMappings) == null, "not null");
var tableMappings = new List<TableMapping>();
entityType.SetRuntimeAnnotation(RelationalAnnotationNames.TableMappings, tableMappings);
entityType.AddRuntimeAnnotation(RelationalAnnotationNames.TableMappings, tableMappings);

var mappingStrategy = entityType.GetMappingStrategy();
var isTpc = mappingStrategy == RelationalAnnotationNames.TpcMappingStrategy;
Expand Down Expand Up @@ -500,8 +500,13 @@ private static void CreateTableMapping(
foreach (var complexProperty in mappedType.GetDeclaredComplexProperties())
{
var complexType = complexProperty.ComplexType;
var complexTableMappings = new List<TableMapping>();
complexType.SetRuntimeAnnotation(RelationalAnnotationNames.TableMappings, complexTableMappings);

var complexTableMappings = (List<TableMapping>?)complexType.FindRuntimeAnnotationValue(RelationalAnnotationNames.TableMappings);
if (complexTableMappings == null)
{
complexTableMappings = [];
complexType.AddRuntimeAnnotation(RelationalAnnotationNames.TableMappings, complexTableMappings);
}

CreateTableMapping(
relationalTypeMappingSource,
Expand Down Expand Up @@ -570,7 +575,7 @@ private static void AddViews(

Check.DebugAssert(entityType.FindRuntimeAnnotationValue(RelationalAnnotationNames.ViewMappings) == null, "not null");
var viewMappings = new List<ViewMapping>();
entityType.SetRuntimeAnnotation(RelationalAnnotationNames.ViewMappings, viewMappings);
entityType.AddRuntimeAnnotation(RelationalAnnotationNames.ViewMappings, viewMappings);

var mappingStrategy = entityType.GetMappingStrategy();
var isTpc = mappingStrategy == RelationalAnnotationNames.TpcMappingStrategy;
Expand Down Expand Up @@ -1061,19 +1066,19 @@ private static void AddStoredProcedures(
if (insertStoredProcedureMappings?.Count > 0)
{
insertStoredProcedureMappings.Reverse();
entityType.SetRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureMappings, insertStoredProcedureMappings);
entityType.AddRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureMappings, insertStoredProcedureMappings);
}

if (deleteStoredProcedureMappings?.Count > 0)
{
deleteStoredProcedureMappings.Reverse();
entityType.SetRuntimeAnnotation(RelationalAnnotationNames.DeleteStoredProcedureMappings, deleteStoredProcedureMappings);
entityType.AddRuntimeAnnotation(RelationalAnnotationNames.DeleteStoredProcedureMappings, deleteStoredProcedureMappings);
}

if (updateStoredProcedureMappings?.Count > 0)
{
updateStoredProcedureMappings.Reverse();
entityType.SetRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureMappings, updateStoredProcedureMappings);
entityType.AddRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureMappings, updateStoredProcedureMappings);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/Metadata/IReadOnlyEntityType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ bool IsAssignableFrom(IReadOnlyEntityType derivedType)
/// <param name="property">The property that the key is defined on.</param>
/// <returns>The key, or null if none is defined.</returns>
IReadOnlyKey? FindKey(IReadOnlyProperty property)
=> FindKey(new[] { property });
=> FindKey([property]);

/// <summary>
/// Gets the primary and alternate keys for this entity type.
Expand Down
47 changes: 42 additions & 5 deletions src/EFCore/Metadata/RuntimeAnnotatableBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System.Collections.Concurrent;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

namespace Microsoft.EntityFrameworkCore.Infrastructure;

Expand All @@ -22,7 +21,7 @@ namespace Microsoft.EntityFrameworkCore.Infrastructure;
/// </remarks>
public class RuntimeAnnotatableBase : IAnnotatable
{
private readonly Dictionary<string, Annotation> _annotations = new(StringComparer.Ordinal);
private Dictionary<string, Annotation>? _annotations;
private ConcurrentDictionary<string, Annotation>? _runtimeAnnotations;

/// <summary>
Expand Down Expand Up @@ -104,6 +103,7 @@ public virtual void SetAnnotation(string name, object? value)
string name,
Annotation annotation)
{
_annotations ??= new(StringComparer.Ordinal);
_annotations[name] = annotation;

return annotation;
Expand All @@ -120,7 +120,7 @@ public virtual void SetAnnotation(string name, object? value)
{
Check.NotEmpty(name, nameof(name));

return _annotations.TryGetValue(name, out var annotation)
return _annotations != null && _annotations.TryGetValue(name, out var annotation)
? annotation
: null;
}
Expand All @@ -143,6 +143,26 @@ public virtual Annotation GetAnnotation(string annotationName)
return annotation;
}

/// <summary>
/// Removes the given annotation from this object.
/// </summary>
/// <param name="name">The annotation to remove.</param>
/// <returns>The annotation that was removed.</returns>
public virtual Annotation? RemoveAnnotation(string name)
{
Check.NotNull(name, nameof(name));

var annotation = FindAnnotation(name);
if (annotation == null)
{
return null;
}

_annotations!.Remove(name);

return annotation;
}

/// <summary>
/// Gets the value annotation with the given name, returning <see langword="null" /> if it does not exist.
/// </summary>
Expand All @@ -151,7 +171,24 @@ public virtual Annotation GetAnnotation(string annotationName)
/// The value of the existing annotation if an annotation with the specified name already exists.
/// Otherwise, <see langword="null" />.
/// </returns>
public virtual object? this[string name] => FindAnnotation(name)?.Value;
public virtual object? this[string name]
{
get => FindAnnotation(name)?.Value;

set
{
Check.NotEmpty(name, nameof(name));

if (value == null)
{
RemoveAnnotation(name);
}
else
{
SetAnnotation(name, value);
}
}
}

/// <summary>
/// Creates a new annotation.
Expand Down Expand Up @@ -330,7 +367,7 @@ private ConcurrentDictionary<string, Annotation> GetOrCreateRuntimeAnnotations()
/// <inheritdoc />
[DebuggerStepThrough]
IEnumerable<IAnnotation> IReadOnlyAnnotatable.GetAnnotations()
=> _annotations.Values.OrderBy(a => a.Name, StringComparer.Ordinal);
=> _annotations?.Values.OrderBy(a => a.Name, StringComparer.Ordinal) ?? Enumerable.Empty<Annotation>();

/// <inheritdoc />
[DebuggerStepThrough]
Expand Down
59 changes: 50 additions & 9 deletions src/EFCore/Metadata/RuntimeEntityType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,12 @@ public RuntimeEntityType(
_serviceProperties = new(servicePropertyCount, StringComparer.Ordinal);
}
_unnamedIndexes = new(unnamedIndexCount, PropertyListComparer.Instance);
if(namedIndexCount > 0)
if (namedIndexCount > 0)
{
_namedIndexes = new(namedIndexCount, StringComparer.Ordinal);
}
_keys = new(keyCount, PropertyListComparer.Instance);
if(triggerPropertyCount > 0)
if (triggerPropertyCount > 0)
{
_triggers = new(triggerPropertyCount, StringComparer.Ordinal);
}
Expand Down Expand Up @@ -168,10 +168,23 @@ public virtual RuntimeKey AddKey(IReadOnlyList<RuntimeProperty> properties)
? key
: BaseType?.FindKey(properties);

private IEnumerable<RuntimeKey> GetDeclaredKeys()
/// <summary>
/// Gets all keys declared on this entity type.
/// </summary>
/// <remarks>
/// This method does not return keys declared on base types.
/// It is useful when iterating over all entity types to avoid processing the same key more than once.
/// Use <see cref="GetKeys" /> to also return keys declared on base types.
/// </remarks>
/// <returns>Declared keys.</returns>
public virtual IEnumerable<RuntimeKey> GetDeclaredKeys()
=> _keys.Values;

private IEnumerable<RuntimeKey> GetKeys()
/// <summary>
/// Gets the primary and alternate keys for this entity type.
/// </summary>
/// <returns>The primary and alternate keys.</returns>
public virtual IEnumerable<RuntimeKey> GetKeys()
=> BaseType?.GetKeys().Concat(_keys.Values) ?? _keys.Values;

/// <summary>
Expand Down Expand Up @@ -268,12 +281,27 @@ private IEnumerable<RuntimeForeignKey> FindForeignKeys(IReadOnlyList<IReadOnlyPr
=> FindDeclaredForeignKey(properties, principalKey, principalEntityType)
?? BaseType?.FindForeignKey(properties, principalKey, principalEntityType);

/// <summary>
/// Gets all foreign keys declared on this entity type..
/// </summary>
/// <remarks>
/// This method does not return foreign keys declared on base types.
/// It is useful when iterating over all entity types to avoid processing the same foreign key more than once.
/// Use <see cref="GetForeignKeys" /> to also return foreign keys declared on base types.
/// </remarks>
/// <returns>Declared foreign keys.</returns>
public virtual List<RuntimeForeignKey> GetDeclaredForeignKeys() => _foreignKeys;

private IEnumerable<RuntimeForeignKey> GetDerivedForeignKeys()
=> !HasDirectlyDerivedTypes
? Enumerable.Empty<RuntimeForeignKey>()
: GetDerivedTypes().Cast<RuntimeEntityType>().SelectMany(et => et._foreignKeys);

private IEnumerable<RuntimeForeignKey> GetForeignKeys()
/// <summary>
/// Gets the foreign keys defined on this entity type.
/// </summary>
/// <returns>The foreign keys defined on this entity type.</returns>
public virtual IEnumerable<RuntimeForeignKey> GetForeignKeys()
=> BaseType != null
? _foreignKeys.Count == 0
? BaseType.GetForeignKeys()
Expand Down Expand Up @@ -560,7 +588,16 @@ public virtual RuntimeIndex AddIndex(
? index
: BaseType?.FindIndex(name);

private IEnumerable<RuntimeIndex> GetDeclaredIndexes()
/// <summary>
/// Gets all indexes declared on this entity type.
/// </summary>
/// <remarks>
/// This method does not return indexes declared on base types.
/// It is useful when iterating over all entity types to avoid processing the same index more than once.
/// Use <see cref="GetForeignKeys" /> to also return indexes declared on base types.
/// </remarks>
/// <returns>Declared indexes.</returns>
public virtual IEnumerable<RuntimeIndex> GetDeclaredIndexes()
=> _namedIndexes == null
? _unnamedIndexes.Values
: _unnamedIndexes.Values.Concat(_namedIndexes.Values);
Expand All @@ -570,7 +607,11 @@ private IEnumerable<RuntimeIndex> GetDerivedIndexes()
? Enumerable.Empty<RuntimeIndex>()
: GetDerivedTypes().Cast<RuntimeEntityType>().SelectMany(et => et.GetDeclaredIndexes());

private IEnumerable<RuntimeIndex> GetIndexes()
/// <summary>
/// Gets the indexes defined on this entity type.
/// </summary>
/// <returns>The indexes defined on this entity type.</returns>
public virtual IEnumerable<RuntimeIndex> GetIndexes()
=> BaseType != null
? _namedIndexes == null
? BaseType.GetIndexes()
Expand Down Expand Up @@ -1057,12 +1098,12 @@ IEnumerable<IForeignKey> IEntityType.GetForeignKeys()
/// <inheritdoc />
[DebuggerStepThrough]
IEnumerable<IReadOnlyForeignKey> IReadOnlyEntityType.GetDeclaredForeignKeys()
=> _foreignKeys;
=> GetDeclaredForeignKeys();

/// <inheritdoc />
[DebuggerStepThrough]
IEnumerable<IForeignKey> IEntityType.GetDeclaredForeignKeys()
=> _foreignKeys;
=> GetDeclaredForeignKeys();

/// <inheritdoc />
[DebuggerStepThrough]
Expand Down
14 changes: 12 additions & 2 deletions src/EFCore/Metadata/RuntimeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,16 @@ private IEnumerable<RuntimeEntityType> FindEntityTypes(Type type)
: result;
}

/// <summary>
/// Gets all entity types defined in the model.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <returns>All entity types defined in the model.</returns>
private IEnumerable<RuntimeEntityType> GetEntityTypes()
=> _entityTypes.Values.OrderBy(e => e.Name, StringComparer.Ordinal);

/// <summary>
/// Adds configuration for a scalar type.
/// </summary>
Expand Down Expand Up @@ -392,12 +402,12 @@ bool IModel.IsIndexerMethod(MethodInfo methodInfo)
/// <inheritdoc />
[DebuggerStepThrough]
IEnumerable<IReadOnlyEntityType> IReadOnlyModel.GetEntityTypes()
=> _entityTypes.Values.OrderBy(e => e.Name, StringComparer.Ordinal);
=> GetEntityTypes();

/// <inheritdoc />
[DebuggerStepThrough]
IEnumerable<IEntityType> IModel.GetEntityTypes()
=> _entityTypes.Values.OrderBy(e => e.Name, StringComparer.Ordinal);
=> GetEntityTypes();

/// <inheritdoc />
[DebuggerStepThrough]
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/Metadata/RuntimeTypeBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ public virtual RuntimeProperty AddProperty(
=> _properties.TryGetValue(name, out var property)
? property
: null;

/// <summary>
/// Gets all scalar properties declared on this type.
/// </summary>
Expand Down
Loading

0 comments on commit 4211953

Please sign in to comment.