Skip to content

Commit

Permalink
Add skip navigation support in Metadata
Browse files Browse the repository at this point in the history
Part of #19003
  • Loading branch information
AndriySvyryd committed Dec 19, 2019
1 parent dc1e811 commit 45dab6c
Show file tree
Hide file tree
Showing 49 changed files with 3,667 additions and 440 deletions.
4 changes: 2 additions & 2 deletions src/EFCore/Extensions/ConventionNavigationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static class ConventionNavigationExtensions
/// The inverse navigation, or <c>null</c> if none is defined.
/// </returns>
public static IConventionNavigation FindInverse([NotNull] this IConventionNavigation navigation)
=> (IConventionNavigation)((INavigation)navigation).FindInverse();
=> ((Navigation)navigation).FindInverse();

/// <summary>
/// Gets the entity type that a given navigation property will hold an instance of
Expand All @@ -31,7 +31,7 @@ public static IConventionNavigation FindInverse([NotNull] this IConventionNaviga
/// <param name="navigation"> The navigation property to find the target entity type of. </param>
/// <returns> The target entity type. </returns>
public static IConventionEntityType GetTargetType([NotNull] this IConventionNavigation navigation)
=> (IConventionEntityType)((INavigation)navigation).GetTargetType();
=> ((Navigation)navigation).GetTargetType();

/// <summary>
/// Sets a value indicating whether this navigation should be eager loaded by default.
Expand Down
4 changes: 2 additions & 2 deletions src/EFCore/Extensions/MutableNavigationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static class MutableNavigationExtensions
/// The inverse navigation, or <c>null</c> if none is defined.
/// </returns>
public static IMutableNavigation FindInverse([NotNull] this IMutableNavigation navigation)
=> (IMutableNavigation)((INavigation)navigation).FindInverse();
=> ((Navigation)navigation).FindInverse();

/// <summary>
/// Gets the entity type that a given navigation property will hold an instance of
Expand All @@ -31,7 +31,7 @@ public static IMutableNavigation FindInverse([NotNull] this IMutableNavigation n
/// <param name="navigation"> The navigation property to find the target entity type of. </param>
/// <returns> The target entity type. </returns>
public static IMutableEntityType GetTargetType([NotNull] this IMutableNavigation navigation)
=> (IMutableEntityType)((INavigation)navigation).GetTargetType();
=> ((Navigation)navigation).GetTargetType();

/// <summary>
/// Sets a value indicating whether this navigation should be eager loaded by default.
Expand Down
16 changes: 2 additions & 14 deletions src/EFCore/Extensions/NavigationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,7 @@ public static bool IsCollection([NotNull] this INavigation navigation)
/// </returns>
[DebuggerStepThrough]
public static INavigation FindInverse([NotNull] this INavigation navigation)
{
Check.NotNull(navigation, nameof(navigation));

return navigation.IsDependentToPrincipal()
? navigation.ForeignKey.PrincipalToDependent
: navigation.ForeignKey.DependentToPrincipal;
}
=> ((Navigation)Check.NotNull(navigation, nameof(navigation))).FindInverse();

/// <summary>
/// Gets the entity type that a given navigation property will hold an instance of
Expand All @@ -78,13 +72,7 @@ public static INavigation FindInverse([NotNull] this INavigation navigation)
/// <returns> The target entity type. </returns>
[DebuggerStepThrough]
public static IEntityType GetTargetType([NotNull] this INavigation navigation)
{
Check.NotNull(navigation, nameof(navigation));

return navigation.IsDependentToPrincipal()
? navigation.ForeignKey.PrincipalEntityType
: navigation.ForeignKey.DeclaringEntityType;
}
=> (Check.NotNull(navigation, nameof(navigation)) as Navigation)?.GetTargetType();

/// <summary>
/// Gets a value indicating whether this navigation should be eager loaded by default.
Expand Down
15 changes: 15 additions & 0 deletions src/EFCore/Infrastructure/ModelValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,21 @@ protected virtual void ValidateRelationships(
: "." + foreignKey.PrincipalToDependent.Name)));
}
}

foreach (var navigation in entityType.GetDeclaredSkipNavigations())
{
if (!navigation.IsCollection)
{
throw new InvalidOperationException(CoreStrings.SkipNavigationNonCollection(
navigation.Name, navigation.DeclaringEntityType.DisplayName()));
}

if (navigation.Inverse == null)
{
throw new InvalidOperationException(CoreStrings.SkipNavigationNoInverse(
navigation.Name, navigation.DeclaringEntityType.DisplayName()));
}
}
}
}

Expand Down
22 changes: 22 additions & 0 deletions src/EFCore/Metadata/Builders/IConventionSkipNavigationBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace Microsoft.EntityFrameworkCore.Metadata.Builders
{
/// <summary>
/// <para>
/// Provides a simple API surface for configuring an <see cref="IConventionSkipNavigation" /> from conventions.
/// </para>
/// <para>
/// This interface is typically used by database providers (and other extensions). It is generally
/// not used in application code.
/// </para>
/// </summary>
public interface IConventionSkipNavigationBuilder : IConventionAnnotatableBuilder
{
/// <summary>
/// The navigation property being configured.
/// </summary>
new IConventionSkipNavigation Metadata { get; }
}
}
35 changes: 35 additions & 0 deletions src/EFCore/Metadata/Conventions/ConventionSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,41 @@ public class ConventionSet
/// </summary>
public virtual IList<INavigationAddedConvention> NavigationAddedConventions { get; } = new List<INavigationAddedConvention>();

/// <summary>
/// Conventions to run when an annotation is changed on a navigation property.
/// </summary>
public virtual IList<INavigationAnnotationChangedConvention> NavigationAnnotationChangedConventions { get; }
= new List<INavigationAnnotationChangedConvention>();

/// <summary>
/// Conventions to run when a navigation property is removed.
/// </summary>
public virtual IList<INavigationRemovedConvention> NavigationRemovedConventions { get; } = new List<INavigationRemovedConvention>();

/// <summary>
/// Conventions to run when a skip navigation property is added.
/// </summary>
public virtual IList<ISkipNavigationAddedConvention> SkipNavigationAddedConventions { get; }
= new List<ISkipNavigationAddedConvention>();

/// <summary>
/// Conventions to run when an annotation is changed on a skip navigation property.
/// </summary>
public virtual IList<ISkipNavigationAnnotationChangedConvention> SkipNavigationAnnotationChangedConventions { get; }
= new List<ISkipNavigationAnnotationChangedConvention>();

/// <summary>
/// Conventions to run when a skip navigation inverse is changed.
/// </summary>
public virtual IList<ISkipNavigationInverseChangedConvention> SkipNavigationInverseChangedConventions { get; }
= new List<ISkipNavigationInverseChangedConvention>();

/// <summary>
/// Conventions to run when a skip navigation property is removed.
/// </summary>
public virtual IList<ISkipNavigationRemovedConvention> SkipNavigationRemovedConventions { get; }
= new List<ISkipNavigationRemovedConvention>();

/// <summary>
/// Conventions to run when a key is added.
/// </summary>
Expand Down Expand Up @@ -187,6 +217,11 @@ public class ConventionSet
public virtual IList<IPropertyAnnotationChangedConvention> PropertyAnnotationChangedConventions { get; }
= new List<IPropertyAnnotationChangedConvention>();

/// <summary>
/// Conventions to run when a property is removed.
/// </summary>
public virtual IList<IPropertyRemovedConvention> PropertyRemovedConventions { get; } = new List<IPropertyRemovedConvention>();

/// <summary>
/// Replaces an existing convention with a derived convention.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
{
/// <summary>
/// Represents an operation that should be performed when an annotation is changed on a navigation.
/// </summary>
public interface INavigationAnnotationChangedConvention : IConvention
{
/// <summary>
/// Called after an annotation is changed on a navigation.
/// </summary>
/// <param name="relationshipBuilder"> The builder for the foreign key. </param>
/// <param name="navigation"> The navigation. </param>
/// <param name="name"> The annotation name. </param>
/// <param name="annotation"> The new annotation. </param>
/// <param name="oldAnnotation"> The old annotation. </param>
/// <param name="context"> Additional information associated with convention execution. </param>
void ProcessNavigationAnnotationChanged(
[NotNull] IConventionRelationshipBuilder relationshipBuilder,
[NotNull] IConventionNavigation navigation,
[NotNull] string name,
[CanBeNull] IConventionAnnotation annotation,
[CanBeNull] IConventionAnnotation oldAnnotation,
[NotNull] IConventionContext<IConventionAnnotation> context);
}
}
25 changes: 25 additions & 0 deletions src/EFCore/Metadata/Conventions/IPropertyRemovedConvention.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
{
/// <summary>
/// Represents an operation that should be performed when a property is removed from the entity type.
/// </summary>
public interface IPropertyRemovedConvention : IConvention
{
/// <summary>
/// Called after a property is removed from the entity type.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type that contained the property. </param>
/// <param name="property"> The removed property. </param>
/// <param name="context"> Additional information associated with convention execution. </param>
void ProcessPropertyRemoved(
[NotNull] IConventionEntityTypeBuilder entityTypeBuilder,
[NotNull] IConventionProperty property,
[NotNull] IConventionContext<IConventionProperty> context);
}
}
23 changes: 23 additions & 0 deletions src/EFCore/Metadata/Conventions/ISkipNavigationAddedConvention.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
{
/// <summary>
/// Represents an operation that should be performed when a skip navigation is added to the entity type.
/// </summary>
public interface ISkipNavigationAddedConvention : IConvention
{
/// <summary>
/// Called after a skip navigation is added to the entity type.
/// </summary>
/// <param name="skipNavigationBuilder"> The builder for the skip navigation. </param>
/// <param name="context"> Additional information associated with convention execution. </param>
void ProcessSkipNavigationAdded(
[NotNull] IConventionSkipNavigationBuilder skipNavigationBuilder,
[NotNull] IConventionContext<IConventionSkipNavigationBuilder> context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
{
/// <summary>
/// Represents an operation that should be performed when an annotation is changed on a skip navigation.
/// </summary>
public interface ISkipNavigationAnnotationChangedConvention : IConvention
{
/// <summary>
/// Called after an annotation is changed on a skip navigation.
/// </summary>
/// <param name="skipNavigationBuilder"> The builder for the skip navigation. </param>
/// <param name="name"> The annotation name. </param>
/// <param name="annotation"> The new annotation. </param>
/// <param name="oldAnnotation"> The old annotation. </param>
/// <param name="context"> Additional information associated with convention execution. </param>
void ProcessSkipNavigationAnnotationChanged(
[NotNull] IConventionSkipNavigationBuilder skipNavigationBuilder,
[NotNull] string name,
[CanBeNull] IConventionAnnotation annotation,
[CanBeNull] IConventionAnnotation oldAnnotation,
[NotNull] IConventionContext<IConventionAnnotation> context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
{
/// <summary>
/// Represents an operation that should be performed when a skip navigation inverse is changed.
/// </summary>
public interface ISkipNavigationInverseChangedConvention : IConvention
{
/// <summary>
/// Called after a skip navigation inverse is changed.
/// </summary>
/// <param name="skipNavigationBuilder"> The builder for the skip navigation. </param>
/// <param name="inverse"> The current inverse skip navigation. </param>
/// <param name="oldInverse"> The old inverse skip navigation. </param>
/// <param name="context"> Additional information associated with convention execution. </param>
void ProcessSkipNavigationInverseChanged(
[NotNull] IConventionSkipNavigationBuilder skipNavigationBuilder,
[NotNull] IConventionSkipNavigation inverse,
[NotNull] IConventionSkipNavigation oldInverse,
[NotNull] IConventionContext<IConventionSkipNavigation> context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
{
/// <summary>
/// Represents an operation that should be performed when a skip navigation is removed from the entity type.
/// </summary>
public interface ISkipNavigationRemovedConvention : IConvention
{
/// <summary>
/// Called after a skip navigation is removed from the entity type.
/// </summary>
/// <param name="entityTypeBuilder"> The builder for the entity type that contained the navigation. </param>
/// <param name="navigation"> The removed navigation. </param>
/// <param name="context"> Additional information associated with convention execution. </param>
void ProcessSkipNavigationRemoved(
[NotNull] IConventionEntityTypeBuilder entityTypeBuilder,
[NotNull] IConventionSkipNavigation navigation,
[NotNull] IConventionContext<IConventionSkipNavigation> context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,31 @@ public abstract string OnNavigationRemoved(
[NotNull] string navigationName,
[CanBeNull] MemberInfo memberInfo);

public abstract IConventionAnnotation OnNavigationAnnotationChanged(
[NotNull] IConventionRelationshipBuilder relationshipBuilder,
[NotNull] IConventionNavigation navigation,
[NotNull] string name,
[CanBeNull] IConventionAnnotation annotation,
[CanBeNull] IConventionAnnotation oldAnnotation);

public abstract IConventionSkipNavigationBuilder OnSkipNavigationAdded(
[NotNull] IConventionSkipNavigationBuilder navigationBuilder);

public abstract IConventionAnnotation OnSkipNavigationAnnotationChanged(
[NotNull] IConventionSkipNavigationBuilder navigationBuilder,
[NotNull] string name,
[CanBeNull] IConventionAnnotation annotation,
[CanBeNull] IConventionAnnotation oldAnnotation);

public abstract IConventionSkipNavigation OnSkipNavigationInverseChanged(
[NotNull] IConventionSkipNavigationBuilder navigationBuilder,
[NotNull] IConventionSkipNavigation inverse,
[NotNull] IConventionSkipNavigation oldInverse);

public abstract IConventionSkipNavigation OnSkipNavigationRemoved(
[NotNull] IConventionEntityTypeBuilder entityTypeBuilder,
[NotNull] IConventionSkipNavigation navigation);

public abstract IConventionPropertyBuilder OnPropertyAdded([NotNull] IConventionPropertyBuilder propertyBuilder);

public abstract IConventionAnnotation OnPropertyAnnotationChanged(
Expand All @@ -153,6 +178,8 @@ public abstract FieldInfo OnPropertyFieldChanged(
[NotNull] IConventionPropertyBuilder propertyBuilder, FieldInfo newFieldInfo, [CanBeNull] FieldInfo oldFieldInfo);

public abstract IConventionPropertyBuilder OnPropertyNullableChanged([NotNull] IConventionPropertyBuilder propertyBuilder);

public abstract IConventionProperty OnPropertyRemoved([NotNull] IConventionEntityTypeBuilder entityTypeBuilder, [NotNull] IConventionProperty property);
}
}
}
Loading

0 comments on commit 45dab6c

Please sign in to comment.