Skip to content

Commit

Permalink
Add complex types
Browse files Browse the repository at this point in the history
Fixes #13947
  • Loading branch information
AndriySvyryd committed May 31, 2023
1 parent 62238db commit 64d0d12
Show file tree
Hide file tree
Showing 169 changed files with 20,138 additions and 6,451 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -711,10 +711,10 @@ protected virtual ModelBuilder VisitForeignKeys(
uniquifier: NavigationUniquifier);

var leftSkipNavigation = leftEntityType.AddSkipNavigation(
leftNavigationPropertyName, null, rightEntityType, collection: true, onDependent: false);
leftNavigationPropertyName, memberInfo: null, targetEntityType: rightEntityType, collection: true, onDependent: false);
leftSkipNavigation.SetForeignKey(fks[0]);
var rightSkipNavigation = rightEntityType.AddSkipNavigation(
rightNavigationPropertyName, null, leftEntityType, collection: true, onDependent: false);
rightNavigationPropertyName, memberInfo: null, targetEntityType: leftEntityType, collection: true, onDependent: false);
rightSkipNavigation.SetForeignKey(fks[1]);
leftSkipNavigation.SetInverse(rightSkipNavigation);
rightSkipNavigation.SetInverse(leftSkipNavigation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ protected override int GetPropertyIndex(IPropertyBase propertyBase)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected override int GetPropertyCount(IEntityType entityType)
=> entityType.ShadowPropertyCount();
protected override int GetPropertyCount(IRuntimeTypeBase typeBase)
=> typeBase.ShadowPropertyCount;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
34 changes: 18 additions & 16 deletions src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
/// </summary>
public sealed partial class InternalEntityEntry : IUpdateEntry
{
// ReSharper disable once FieldCanBeMadeReadOnly.Local
private readonly StateData _stateData;
private OriginalValues _originalValues;
private RelationshipsSnapshot _relationshipsSnapshot;
Expand All @@ -39,10 +38,10 @@ public InternalEntityEntry(
object entity)
{
StateManager = stateManager;
EntityType = entityType;
EntityType = (IRuntimeEntityType)entityType;
Entity = entity;
_shadowValues = entityType.GetEmptyShadowValuesFactory()();
_stateData = new StateData(entityType.PropertyCount(), entityType.NavigationCount());
_shadowValues = EntityType.EmptyShadowValuesFactory();
_stateData = new StateData(EntityType.PropertyCount, EntityType.NavigationCount);

MarkShadowPropertiesNotSet(entityType);
}
Expand All @@ -60,10 +59,10 @@ public InternalEntityEntry(
in ValueBuffer valueBuffer)
{
StateManager = stateManager;
EntityType = entityType;
EntityType = (IRuntimeEntityType)entityType;
Entity = entity;
_shadowValues = ((IRuntimeEntityType)entityType).ShadowValuesFactory(valueBuffer);
_stateData = new StateData(entityType.PropertyCount(), entityType.NavigationCount());
_shadowValues = EntityType.ShadowValuesFactory(valueBuffer);
_stateData = new StateData(EntityType.PropertyCount, EntityType.NavigationCount);
}

/// <summary>
Expand Down Expand Up @@ -107,7 +106,7 @@ void IUpdateEntry.SetPropertyModified(IProperty property)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public IEntityType EntityType { [DebuggerStepThrough] get; }
public IRuntimeEntityType EntityType { get; }

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down Expand Up @@ -271,7 +270,7 @@ private bool PrepareForAdd(EntityState newState)
if (EntityState == EntityState.Modified)
{
_stateData.FlagAllProperties(
EntityType.PropertyCount(), PropertyFlag.Modified,
EntityType.PropertyCount, PropertyFlag.Modified,
flagged: false);
}

Expand Down Expand Up @@ -309,7 +308,7 @@ private void SetEntityState(EntityState oldState, EntityState newState, bool acc
if (newState == EntityState.Modified
&& modifyProperties)
{
_stateData.FlagAllProperties(entityType.PropertyCount(), PropertyFlag.Modified, flagged: true);
_stateData.FlagAllProperties(EntityType.PropertyCount, PropertyFlag.Modified, flagged: true);

// Hot path; do not use LINQ
foreach (var property in entityType.GetProperties())
Expand All @@ -329,7 +328,7 @@ private void SetEntityState(EntityState oldState, EntityState newState, bool acc
if (newState == EntityState.Unchanged)
{
_stateData.FlagAllProperties(
entityType.PropertyCount(), PropertyFlag.Modified,
EntityType.PropertyCount, PropertyFlag.Modified,
flagged: false);
}

Expand Down Expand Up @@ -372,7 +371,7 @@ private void SetEntityState(EntityState oldState, EntityState newState, bool acc
|| newState == EntityState.Detached)
&& HasConceptualNull)
{
_stateData.FlagAllProperties(entityType.PropertyCount(), PropertyFlag.Null, flagged: false);
_stateData.FlagAllProperties(EntityType.PropertyCount, PropertyFlag.Null, flagged: false);
}

if (oldState == EntityState.Detached
Expand Down Expand Up @@ -1476,9 +1475,9 @@ public void AcceptChanges()
_temporaryValues = new SidecarValues();
}

_stateData.FlagAllProperties(EntityType.PropertyCount(), PropertyFlag.IsStoreGenerated, false);
_stateData.FlagAllProperties(EntityType.PropertyCount(), PropertyFlag.IsTemporary, false);
_stateData.FlagAllProperties(EntityType.PropertyCount(), PropertyFlag.Unknown, false);
_stateData.FlagAllProperties(EntityType.PropertyCount, PropertyFlag.IsStoreGenerated, false);
_stateData.FlagAllProperties(EntityType.PropertyCount, PropertyFlag.IsTemporary, false);
_stateData.FlagAllProperties(EntityType.PropertyCount, PropertyFlag.Unknown, false);

var currentState = EntityState;
switch (currentState)
Expand Down Expand Up @@ -1698,7 +1697,7 @@ public void DiscardStoreGeneratedValues()
if (!_storeGeneratedValues.IsEmpty)
{
_storeGeneratedValues = new SidecarValues();
_stateData.FlagAllProperties(EntityType.PropertyCount(), PropertyFlag.IsStoreGenerated, false);
_stateData.FlagAllProperties(EntityType.PropertyCount, PropertyFlag.IsStoreGenerated, false);
}
}

Expand Down Expand Up @@ -2007,6 +2006,9 @@ public DebugView DebugView
IUpdateEntry? IUpdateEntry.SharedIdentityEntry
=> SharedIdentityEntry;

IEntityType IUpdateEntry.EntityType
=> EntityType;

private enum CurrentValueType
{
Normal,
Expand Down
4 changes: 2 additions & 2 deletions src/EFCore/ChangeTracking/Internal/KeyPropagator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public KeyPropagator(
{
Check.DebugAssert(property.IsForeignKey(), $"property {property} is not part of an FK");

var generationProperty = property.FindGenerationProperty();
var generationProperty = (IProperty?)property.FindGenerationProperty();
var principalEntry = TryPropagateValue(entry, property, generationProperty);

if (principalEntry == null
Expand Down Expand Up @@ -73,7 +73,7 @@ public KeyPropagator(
{
Check.DebugAssert(property.IsForeignKey(), $"property {property} is not part of an FK");

var generationProperty = property.FindGenerationProperty();
var generationProperty = (IProperty?)property.FindGenerationProperty();
var principalEntry = TryPropagateValue(entry, property, generationProperty);

if (principalEntry == null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ protected override int GetPropertyIndex(IPropertyBase propertyBase)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected override int GetPropertyCount(IEntityType entityType)
=> entityType.OriginalValueCount();
protected override int GetPropertyCount(IRuntimeTypeBase typeBase)
=> typeBase.OriginalValueCount;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ protected override int GetPropertyIndex(IPropertyBase propertyBase)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected override int GetPropertyCount(IEntityType entityType)
=> entityType.RelationshipPropertyCount();
protected override int GetPropertyCount(IRuntimeTypeBase typeBase)
=> typeBase.RelationshipPropertyCount;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ protected override int GetPropertyIndex(IPropertyBase propertyBase)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected override int GetPropertyCount(IEntityType entityType)
=> entityType.ShadowPropertyCount();
protected override int GetPropertyCount(IRuntimeTypeBase typeBase)
=> typeBase.ShadowPropertyCount;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ protected override int GetPropertyIndex(IPropertyBase propertyBase)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected override int GetPropertyCount(IEntityType entityType)
=> entityType.StoreGeneratedCount();
protected override int GetPropertyCount(IRuntimeTypeBase typeBase)
=> typeBase.StoreGeneratedCount;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
18 changes: 9 additions & 9 deletions src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ public abstract class SnapshotFactoryFactory
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual Func<ISnapshot> CreateEmpty(IEntityType entityType)
=> GetPropertyCount(entityType) == 0
public virtual Func<ISnapshot> CreateEmpty(IRuntimeTypeBase typeBase)
=> GetPropertyCount(typeBase) == 0
? (() => Snapshot.Empty)
: Expression.Lambda<Func<ISnapshot>>(
CreateConstructorExpression(entityType, null!))
CreateConstructorExpression(typeBase, null!))
.Compile();

/// <summary>
Expand All @@ -35,15 +35,15 @@ public virtual Func<ISnapshot> CreateEmpty(IEntityType entityType)
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected virtual Expression CreateConstructorExpression(
IEntityType entityType,
IRuntimeTypeBase typeBase,
ParameterExpression? parameter)
{
var count = GetPropertyCount(entityType);
var count = GetPropertyCount(typeBase);

var types = new Type[count];
var propertyBases = new IPropertyBase?[count];

foreach (var propertyBase in entityType.GetPropertiesAndNavigations())
foreach (var propertyBase in typeBase.GetSnapshottableMembers())
{
var index = GetPropertyIndex(propertyBase);
if (index >= 0)
Expand All @@ -62,7 +62,7 @@ protected virtual Expression CreateConstructorExpression(
{
snapshotExpressions.Add(
CreateSnapshotExpression(
entityType.ClrType,
typeBase.ClrType,
parameter,
types.Skip(i).Take(Snapshot.MaxGenericTypes).ToArray(),
propertyBases.Skip(i).Take(Snapshot.MaxGenericTypes).ToList()));
Expand All @@ -77,7 +77,7 @@ protected virtual Expression CreateConstructorExpression(
}
else
{
constructorExpression = CreateSnapshotExpression(entityType.ClrType, parameter, types, propertyBases);
constructorExpression = CreateSnapshotExpression(typeBase.ClrType, parameter, types, propertyBases);
}

return constructorExpression;
Expand Down Expand Up @@ -257,7 +257,7 @@ protected virtual Expression CreateReadValueExpression(
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected abstract int GetPropertyCount(IEntityType entityType);
protected abstract int GetPropertyCount(IRuntimeTypeBase typeBase);

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
8 changes: 5 additions & 3 deletions src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory`.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Metadata.Internal;

namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal;

/// <summary>
Expand All @@ -17,17 +19,17 @@ public abstract class SnapshotFactoryFactory<TInput> : SnapshotFactoryFactory
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual Func<TInput, ISnapshot> Create(IEntityType entityType)
public virtual Func<TInput, ISnapshot> Create(IRuntimeTypeBase typeBase)
{
if (GetPropertyCount(entityType) == 0)
if (GetPropertyCount(typeBase) == 0)
{
return _ => Snapshot.Empty;
}

var parameter = Expression.Parameter(typeof(TInput), "source");

return Expression.Lambda<Func<TInput, ISnapshot>>(
CreateConstructorExpression(entityType, parameter),
CreateConstructorExpression(typeBase, parameter),
parameter)
.Compile();
}
Expand Down
5 changes: 3 additions & 2 deletions src/EFCore/ChangeTracking/Internal/StateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,9 @@ public virtual InternalEntityEntry GetOrCreateEntry(object entity, IEntityType?
public virtual InternalEntityEntry CreateEntry(IDictionary<string, object?> values, IEntityType entityType)
{
var i = 0;
var valuesArray = new object?[entityType.PropertyCount()];
var shadowPropertyValuesArray = new object?[entityType.ShadowPropertyCount()];
var runtimeEntityType = (IRuntimeEntityType)entityType;
var valuesArray = new object?[runtimeEntityType.PropertyCount];
var shadowPropertyValuesArray = new object?[runtimeEntityType.ShadowPropertyCount];
foreach (var property in entityType.GetProperties())
{
valuesArray[i++] = values.TryGetValue(property.Name, out var value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static class ValueComparerExtensions
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static ValueComparer? ToNullableComparer(this ValueComparer? valueComparer, IReadOnlyProperty property)
public static ValueComparer? ToNullableComparer(this ValueComparer? valueComparer, IReadOnlyPrimitivePropertyBase property)
{
if (valueComparer == null
|| !property.ClrType.IsNullableValueType()
Expand Down
34 changes: 34 additions & 0 deletions src/EFCore/Diagnostics/ComplexPropertyEventData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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.Diagnostics;

/// <summary>
/// A <see cref="DiagnosticSource" /> event payload class for events that have
/// a property.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-diagnostics">Logging, events, and diagnostics</see> for more information and examples.
/// </remarks>
public class ComplexPropertyEventData : EventData
{
/// <summary>
/// Constructs the event payload.
/// </summary>
/// <param name="eventDefinition">The event definition.</param>
/// <param name="messageGenerator">A delegate that generates a log message for this event.</param>
/// <param name="property">The property.</param>
public ComplexPropertyEventData(
EventDefinitionBase eventDefinition,
Func<EventDefinitionBase, EventData, string> messageGenerator,
IReadOnlyComplexProperty property)
: base(eventDefinition, messageGenerator)
{
Property = property;
}

/// <summary>
/// The property.
/// </summary>
public virtual IReadOnlyComplexProperty Property { get; }
}
20 changes: 19 additions & 1 deletion src/EFCore/Diagnostics/CoreEventId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ private enum Id
MappedEntityTypeIgnoredWarning,
MappedNavigationIgnoredWarning,
MappedPropertyIgnoredWarning,
MappedComplexPropertyIgnoredWarning,

// ChangeTracking events
DetectChangesStarting = CoreBaseId + 800,
Expand Down Expand Up @@ -557,7 +558,7 @@ private static EventId MakeModelValidationId(Id id)
/// This event is in the <see cref="DbLoggerCategory.Model" /> category.
/// </para>
/// <para>
/// This event uses the <see cref="PropertyEventData" /> payload when used with a <see cref="DiagnosticSource" />.
/// This event uses the <see cref="PrimitivePropertyEventData" /> payload when used with a <see cref="DiagnosticSource" />.
/// </para>
/// <para>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and
Expand All @@ -566,6 +567,23 @@ private static EventId MakeModelValidationId(Id id)
/// </remarks>
public static readonly EventId MappedPropertyIgnoredWarning = MakeModelId(Id.MappedPropertyIgnoredWarning);

/// <summary>
/// A property was first mapped explicitly and then ignored.
/// </summary>
/// <remarks>
/// <para>
/// This event is in the <see cref="DbLoggerCategory.Model" /> category.
/// </para>
/// <para>
/// This event uses the <see cref="ComplexPropertyEventData" /> payload when used with a <see cref="DiagnosticSource" />.
/// </para>
/// <para>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and
/// examples.
/// </para>
/// </remarks>
public static readonly EventId MappedComplexPropertyIgnoredWarning = MakeModelId(Id.MappedComplexPropertyIgnoredWarning);

/// <summary>
/// An index was not created as the properties are already covered.
/// </summary>
Expand Down
Loading

0 comments on commit 64d0d12

Please sign in to comment.