Skip to content

Commit f912b4f

Browse files
committed
Introduce IStructuralProperty
Add support for property bag complex types Throw for shadow properties on complex types Fixes #31237
1 parent ce56d77 commit f912b4f

34 files changed

+1152
-245
lines changed

src/EFCore.Relational/Query/CollectionResultExpression.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace Microsoft.EntityFrameworkCore.Query;
1818
/// <param name="elementType">The clr type of individual elements in the collection.</param>
1919
public class CollectionResultExpression(
2020
Expression queryExpression,
21-
IPropertyBase? relationship,
21+
IStructuralProperty? relationship,
2222
Type elementType)
2323
: Expression, IPrintableExpression
2424
{
@@ -30,7 +30,7 @@ public class CollectionResultExpression(
3030
/// <summary>
3131
/// The relationship associated with the collection, if any.
3232
/// </summary>
33-
public virtual IPropertyBase? Relationship { get; } = relationship;
33+
public virtual IStructuralProperty? Relationship { get; } = relationship;
3434

3535
/// <summary>
3636
/// The clr type of elements of the collection.

src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -759,17 +759,11 @@ protected override Expression VisitExtension(Expression extensionExpression)
759759
case CollectionResultExpression
760760
{
761761
QueryExpression: ProjectionBindingExpression projectionBindingExpression,
762-
Relationship: IPropertyBase relationship,
762+
Relationship: IStructuralProperty relationship,
763763
} collectionResult
764764
when GetProjectionIndex(projectionBindingExpression) is JsonProjectionInfo jsonProjectionInfo:
765765
{
766-
var relatedStructuralType = relationship switch
767-
{
768-
IComplexProperty complexProperty => (ITypeBase)complexProperty.ComplexType,
769-
INavigation navigation => navigation.TargetEntityType,
770-
771-
_ => throw new UnreachableException()
772-
};
766+
var relatedStructuralType = relationship.TargetType;
773767

774768
// Disallow tracking queries to project owned entities (but not complex types)
775769
if (relatedStructuralType is IEntityType && _isTracking)

src/EFCore/Infrastructure/ModelValidator.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,14 @@ protected virtual void ValidatePropertyMapping(IConventionComplexProperty comple
354354
CoreStrings.ComplexValueTypeShadowProperty(complexProperty.ComplexType.DisplayName(), shadowProperty.Name));
355355
}
356356
}
357+
358+
// Issue #35613: Shadow properties on all complex types are not supported
359+
var shadowPropertyOnComplexType = complexProperty.ComplexType.GetDeclaredProperties().FirstOrDefault(p => p.IsShadowProperty());
360+
if (shadowPropertyOnComplexType != null)
361+
{
362+
throw new InvalidOperationException(
363+
CoreStrings.ComplexTypeShadowProperty(complexProperty.ComplexType.DisplayName(), shadowPropertyOnComplexType.Name));
364+
}
357365
}
358366

359367
/// <summary>

src/EFCore/Metadata/IComplexProperty.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,17 @@ namespace Microsoft.EntityFrameworkCore.Metadata;
99
/// <remarks>
1010
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
1111
/// </remarks>
12-
public interface IComplexProperty : IReadOnlyComplexProperty, IPropertyBase
12+
public interface IComplexProperty : IReadOnlyComplexProperty, IStructuralProperty
1313
{
1414
/// <summary>
1515
/// Gets the associated complex type.
1616
/// </summary>
1717
new IComplexType ComplexType { get; }
18+
19+
/// <inheritdoc />
20+
ITypeBase IStructuralProperty.TargetType
21+
{
22+
[DebuggerStepThrough]
23+
get => ComplexType;
24+
}
1825
}

src/EFCore/Metadata/IConventionComplexProperty.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata;
1515
/// See <see href="https://aka.ms/efcore-docs-conventions">Model building conventions</see> for more information and examples.
1616
/// </para>
1717
/// </remarks>
18-
public interface IConventionComplexProperty : IReadOnlyComplexProperty, IConventionPropertyBase
18+
public interface IConventionComplexProperty : IReadOnlyComplexProperty, IConventionStructuralProperty
1919
{
2020
/// <summary>
2121
/// Gets the builder that can be used to configure this property.
@@ -44,4 +44,11 @@ public interface IConventionComplexProperty : IReadOnlyComplexProperty, IConvent
4444
/// </summary>
4545
/// <returns>The configuration source for <see cref="IReadOnlyProperty.IsNullable" />.</returns>
4646
ConfigurationSource? GetIsNullableConfigurationSource();
47+
48+
/// <inheritdoc />
49+
IConventionTypeBase IConventionStructuralProperty.TargetType
50+
{
51+
[DebuggerStepThrough]
52+
get => ComplexType;
53+
}
4754
}

src/EFCore/Metadata/IConventionNavigationBase.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,24 @@ namespace Microsoft.EntityFrameworkCore.Metadata;
1717
/// See <see href="https://aka.ms/efcore-docs-conventions">Model building conventions</see> for more information and examples.
1818
/// </para>
1919
/// </remarks>
20-
public interface IConventionNavigationBase : IReadOnlyNavigationBase, IConventionPropertyBase
20+
public interface IConventionNavigationBase : IReadOnlyNavigationBase, IConventionStructuralProperty
2121
{
22+
/// <summary>
23+
/// Gets the entity type that this navigation property will hold an instance(s) of.
24+
/// </summary>
25+
new IConventionEntityType TargetEntityType
26+
{
27+
[DebuggerStepThrough]
28+
get => (IConventionEntityType)((IReadOnlyNavigationBase)this).TargetEntityType;
29+
}
30+
31+
/// <inheritdoc />
32+
IConventionTypeBase IConventionStructuralProperty.TargetType
33+
{
34+
[DebuggerStepThrough]
35+
get => TargetEntityType;
36+
}
37+
2238
/// <summary>
2339
/// Sets a value indicating whether this navigation should be eager loaded by default.
2440
/// </summary>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.EntityFrameworkCore.Metadata;
5+
6+
/// <summary>
7+
/// Represents a structural property that refers to a type.
8+
/// </summary>
9+
/// <remarks>
10+
/// <para>
11+
/// This interface is used during model creation and allows the metadata to be modified.
12+
/// Once the model is built, <see cref="IReadOnlyStructuralProperty" /> represents a read-only view of the same metadata.
13+
/// </para>
14+
/// <para>
15+
/// See <see href="https://aka.ms/efcore-docs-conventions">Model building conventions</see> for more information and examples.
16+
/// </para>
17+
/// </remarks>
18+
public interface IConventionStructuralProperty : IReadOnlyStructuralProperty, IConventionPropertyBase
19+
{
20+
/// <summary>
21+
/// Gets the type that this structural property refers to.
22+
/// </summary>
23+
new IConventionTypeBase TargetType { get; }
24+
}

src/EFCore/Metadata/IMutableComplexProperty.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata;
1616
/// examples.
1717
/// </para>
1818
/// </remarks>
19-
public interface IMutableComplexProperty : IReadOnlyComplexProperty, IMutablePropertyBase
19+
public interface IMutableComplexProperty : IReadOnlyComplexProperty, IMutableStructuralProperty
2020
{
2121
/// <summary>
2222
/// Gets the associated complex type.
@@ -31,4 +31,11 @@ public interface IMutableComplexProperty : IReadOnlyComplexProperty, IMutablePro
3131
/// <inheritdoc />
3232
bool IReadOnlyComplexProperty.IsNullable
3333
=> IsNullable;
34+
35+
/// <inheritdoc />
36+
IMutableTypeBase IMutableStructuralProperty.TargetType
37+
{
38+
[DebuggerStepThrough]
39+
get => ComplexType;
40+
}
3441
}

src/EFCore/Metadata/IMutableNavigationBase.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,24 @@ namespace Microsoft.EntityFrameworkCore.Metadata;
1818
/// examples.
1919
/// </para>
2020
/// </remarks>
21-
public interface IMutableNavigationBase : IReadOnlyNavigationBase, IMutablePropertyBase
21+
public interface IMutableNavigationBase : IReadOnlyNavigationBase, IMutableStructuralProperty
2222
{
23+
/// <summary>
24+
/// Gets the entity type that this navigation property will hold an instance(s) of.
25+
/// </summary>
26+
new IMutableEntityType TargetEntityType
27+
{
28+
[DebuggerStepThrough]
29+
get => (IMutableEntityType)((IReadOnlyNavigationBase)this).TargetEntityType;
30+
}
31+
32+
/// <inheritdoc />
33+
IMutableTypeBase IMutableStructuralProperty.TargetType
34+
{
35+
[DebuggerStepThrough]
36+
get => TargetEntityType;
37+
}
38+
2339
/// <summary>
2440
/// Sets a value indicating whether this navigation should be eager loaded by default.
2541
/// </summary>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.EntityFrameworkCore.Metadata;
5+
6+
/// <summary>
7+
/// Represents a structural property that refers to a type.
8+
/// </summary>
9+
/// <remarks>
10+
/// <para>
11+
/// This interface is used during model creation and allows the metadata to be modified.
12+
/// Once the model is built, <see cref="IReadOnlyStructuralProperty" /> represents a read-only view of the same metadata.
13+
/// </para>
14+
/// <para>
15+
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and
16+
/// examples.
17+
/// </para>
18+
/// </remarks>
19+
public interface IMutableStructuralProperty : IReadOnlyStructuralProperty, IMutablePropertyBase
20+
{
21+
/// <summary>
22+
/// Gets the type that this structural property refers to.
23+
/// </summary>
24+
new IMutableTypeBase TargetType { get; }
25+
}

0 commit comments

Comments
 (0)