Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partial Fix for 6674. Allow inline configuration of Navigations as they are created #20195

Merged
merged 6 commits into from
Mar 8, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions src/EFCore/Metadata/Builders/CollectionNavigationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,28 @@ public CollectionNavigationBuilder(
/// The name of the reference navigation property on the other end of this relationship.
/// If null or not specified, then there is no navigation property on the other end of the relationship.
/// </param>
/// <param name="navigationConfiguration">
/// An optional action which further configures the navigation property.
/// </param>
/// <returns> An object to further configure the relationship. </returns>
public virtual ReferenceCollectionBuilder WithOne([CanBeNull] string navigationName = null)
=> new ReferenceCollectionBuilder(
public virtual ReferenceCollectionBuilder WithOne(
[CanBeNull] string navigationName = null,
[CanBeNull] Action<NavigationBuilder> navigationConfiguration = null)
{
var foreignKey = WithOneBuilder(Check.NullButNotEmpty(navigationName, nameof(navigationName))).Metadata;

if (navigationConfiguration != null
&& foreignKey?.DependentToPrincipal != null)
lajones marked this conversation as resolved.
Show resolved Hide resolved
{
navigationConfiguration(
new NavigationBuilder(foreignKey.DependentToPrincipal));
}

return new ReferenceCollectionBuilder(
DeclaringEntityType,
RelatedEntityType,
WithOneBuilder(Check.NullButNotEmpty(navigationName, nameof(navigationName))).Metadata);
foreignKey);
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
44 changes: 38 additions & 6 deletions src/EFCore/Metadata/Builders/CollectionNavigationBuilder`.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,28 @@ public CollectionNavigationBuilder(
/// The name of the reference navigation property on the other end of this relationship.
/// If null, there is no navigation property on the other end of the relationship.
/// </param>
/// <param name="navigationConfiguration">
/// An optional action which further configures the navigation property.
/// </param>
/// <returns> An object to further configure the relationship. </returns>
public new virtual ReferenceCollectionBuilder<TEntity, TRelatedEntity> WithOne([CanBeNull] string navigationName = null)
=> new ReferenceCollectionBuilder<TEntity, TRelatedEntity>(
public new virtual ReferenceCollectionBuilder<TEntity, TRelatedEntity> WithOne(
[CanBeNull] string navigationName = null,
[CanBeNull] Action<NavigationBuilder> navigationConfiguration = null)
{
var foreignKey = WithOneBuilder(Check.NullButNotEmpty(navigationName, nameof(navigationName))).Metadata;
lajones marked this conversation as resolved.
Show resolved Hide resolved

if (navigationConfiguration != null
&& foreignKey?.DependentToPrincipal != null)
{
navigationConfiguration(
new NavigationBuilder(foreignKey.DependentToPrincipal));
}

return new ReferenceCollectionBuilder<TEntity, TRelatedEntity>(
DeclaringEntityType,
RelatedEntityType,
WithOneBuilder(Check.NullButNotEmpty(navigationName, nameof(navigationName))).Metadata);
foreignKey);
}

/// <summary>
/// <para>
Expand All @@ -72,13 +88,29 @@ public CollectionNavigationBuilder(
/// relationship (<c>post => post.Blog</c>). If no property is specified, the relationship will be
/// configured without a navigation property on the other end of the relationship.
/// </param>
/// <param name="navigationConfiguration">
/// An optional action which further configures the navigation property.
/// </param>
/// <returns> An object to further configure the relationship. </returns>
public virtual ReferenceCollectionBuilder<TEntity, TRelatedEntity> WithOne(
[CanBeNull] Expression<Func<TRelatedEntity, TEntity>> navigationExpression)
=> new ReferenceCollectionBuilder<TEntity, TRelatedEntity>(
[CanBeNull] Expression<Func<TRelatedEntity, TEntity>> navigationExpression,
[CanBeNull] Action<NavigationBuilder> navigationConfiguration = null)
{
var navigationMember = navigationExpression?.GetPropertyAccess();
lajones marked this conversation as resolved.
Show resolved Hide resolved
var foreignKey = WithOneBuilder(navigationMember).Metadata;

if (navigationConfiguration != null
&& foreignKey?.DependentToPrincipal != null)
{
navigationConfiguration(
new NavigationBuilder(foreignKey.DependentToPrincipal));
}

return new ReferenceCollectionBuilder<TEntity, TRelatedEntity>(
DeclaringEntityType,
RelatedEntityType,
WithOneBuilder(navigationExpression?.GetPropertyAccess()).Metadata);
foreignKey);
}

/// <summary>
/// Configures this as a many-to-many relationship.
Expand Down
97 changes: 76 additions & 21 deletions src/EFCore/Metadata/Builders/EntityTypeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -575,23 +575,35 @@ private OwnedNavigationBuilder OwnsManyBuilder(in TypeIdentity ownedType, string
/// no property is specified, the relationship will be configured without a navigation property on this
/// end.
/// </param>
/// <param name="navigationConfiguration">
/// An optional action which further configures the navigation property.
/// </param>
/// <returns> An object that can be used to configure the relationship. </returns>
public virtual ReferenceNavigationBuilder HasOne(
[NotNull] string relatedTypeName,
[CanBeNull] string navigationName)
[CanBeNull] string navigationName,
[CanBeNull] Action<NavigationBuilder> navigationConfiguration = null)
{
Check.NotEmpty(relatedTypeName, nameof(relatedTypeName));
Check.NullButNotEmpty(navigationName, nameof(navigationName));

var relatedEntityType = FindRelatedEntityType(relatedTypeName, navigationName);
var foreignKey = Builder.HasRelationship(
relatedEntityType, navigationName, ConfigurationSource.Explicit,
targetIsPrincipal: Builder.Metadata == relatedEntityType ? true : (bool?)null).Metadata;

if (navigationConfiguration != null
&& foreignKey?.DependentToPrincipal != null)
{
lajones marked this conversation as resolved.
Show resolved Hide resolved
navigationConfiguration(
new NavigationBuilder(foreignKey.DependentToPrincipal));
}

return new ReferenceNavigationBuilder(
Builder.Metadata,
relatedEntityType,
navigationName,
Builder.HasRelationship(
relatedEntityType, navigationName, ConfigurationSource.Explicit,
targetIsPrincipal: Builder.Metadata == relatedEntityType ? true : (bool?)null).Metadata);
foreignKey);
}

/// <summary>
Expand All @@ -618,23 +630,35 @@ public virtual ReferenceNavigationBuilder HasOne(
/// no property is specified, the relationship will be configured without a navigation property on this
/// end.
/// </param>
/// <param name="navigationConfiguration">
/// An optional action which further configures the navigation property.
/// </param>
/// <returns> An object that can be used to configure the relationship. </returns>
public virtual ReferenceNavigationBuilder HasOne(
[NotNull] Type relatedType,
[CanBeNull] string navigationName = null)
[CanBeNull] string navigationName = null,
[CanBeNull] Action<NavigationBuilder> navigationConfiguration = null)
{
Check.NotNull(relatedType, nameof(relatedType));
Check.NullButNotEmpty(navigationName, nameof(navigationName));

var relatedEntityType = FindRelatedEntityType(relatedType, navigationName);
var foreignKey = Builder.HasRelationship(
relatedEntityType, navigationName, ConfigurationSource.Explicit,
targetIsPrincipal: Builder.Metadata == relatedEntityType ? true : (bool?)null).Metadata;

if (navigationConfiguration != null
&& foreignKey?.DependentToPrincipal != null)
{
navigationConfiguration(
new NavigationBuilder(foreignKey.DependentToPrincipal));
}

return new ReferenceNavigationBuilder(
Builder.Metadata,
relatedEntityType,
navigationName,
Builder.HasRelationship(
relatedEntityType, navigationName, ConfigurationSource.Explicit,
targetIsPrincipal: Builder.Metadata == relatedEntityType ? true : (bool?)null).Metadata);
foreignKey);
}

/// <summary>
Expand All @@ -654,15 +678,19 @@ public virtual ReferenceNavigationBuilder HasOne(
/// The name of the reference navigation property on this entity type that represents
/// the relationship. The navigation must be a CLR property on the entity type.
/// </param>
/// <param name="navigationConfiguration">
/// An optional action which further configures the navigation property.
/// </param>
/// <returns> An object that can be used to configure the relationship. </returns>
public virtual ReferenceNavigationBuilder HasOne(
[NotNull] string navigationName)
[NotNull] string navigationName,
[CanBeNull] Action<NavigationBuilder> navigationConfiguration = null)
{
Check.NotEmpty(navigationName, nameof(navigationName));

return Metadata.ClrType == null
? HasOne(navigationName, null) // Path only used by pre 3.0 snapshots
: HasOne(Metadata.GetNavigationMemberInfo(navigationName).GetMemberType(), navigationName);
? HasOne(navigationName, null, navigationConfiguration) // Path only used by pre 3.0 snapshots
: HasOne(Metadata.GetNavigationMemberInfo(navigationName).GetMemberType(), navigationName, navigationConfiguration);
}

/// <summary>
Expand All @@ -683,15 +711,21 @@ public virtual ReferenceNavigationBuilder HasOne(
/// no property is specified, the relationship will be configured without a navigation property on this
/// end.
/// </param>
/// <param name="navigationConfiguration">
/// An optional action which further configures the navigation property.
/// </param>
/// <returns> An object that can be used to configure the relationship. </returns>
public virtual CollectionNavigationBuilder HasMany(
[NotNull] string relatedTypeName,
[CanBeNull] string navigationName)
[CanBeNull] string navigationName,
[CanBeNull] Action<NavigationBuilder> navigationConfiguration = null)
{
Check.NotEmpty(relatedTypeName, nameof(relatedTypeName));
Check.NullButNotEmpty(navigationName, nameof(navigationName));

return HasMany(navigationName, FindRelatedEntityType(relatedTypeName, navigationName));
return HasMany(navigationName,
FindRelatedEntityType(relatedTypeName, navigationName),
navigationConfiguration);
}

/// <summary>
Expand All @@ -710,15 +744,19 @@ public virtual CollectionNavigationBuilder HasMany(
/// The name of the collection navigation property on this entity type that represents the relationship.
/// The navigation must be a CLR property on the entity type.
/// </param>
/// <param name="navigationConfiguration">
/// An optional action which further configures the navigation property.
/// </param>
/// <returns> An object that can be used to configure the relationship. </returns>
public virtual CollectionNavigationBuilder HasMany(
[NotNull] string navigationName)
[NotNull] string navigationName,
[CanBeNull] Action<NavigationBuilder> navigationConfiguration = null)
{
Check.NotEmpty(navigationName, nameof(navigationName));

if (Metadata.ClrType == null)
{
return HasMany(navigationName, (string)null);
return HasMany(navigationName, (string)null, navigationConfiguration);
}

var memberType = Metadata.GetNavigationMemberInfo(navigationName).GetMemberType();
Expand All @@ -734,7 +772,7 @@ public virtual CollectionNavigationBuilder HasMany(
"T"));
}

return HasMany(elementType, navigationName);
return HasMany(elementType, navigationName, navigationConfiguration);
}

/// <summary>
Expand All @@ -760,18 +798,27 @@ public virtual CollectionNavigationBuilder HasMany(
/// no property is specified, the relationship will be configured without a navigation property on this
/// end.
/// </param>
/// <param name="navigationConfiguration">
/// An optional action which further configures the navigation property.
/// </param>
/// <returns> An object that can be used to configure the relationship. </returns>
public virtual CollectionNavigationBuilder HasMany(
[NotNull] Type relatedType,
[CanBeNull] string navigationName = null)
[CanBeNull] string navigationName = null,
[CanBeNull] Action<NavigationBuilder> navigationConfiguration = null)
{
Check.NotNull(relatedType, nameof(relatedType));
Check.NullButNotEmpty(navigationName, nameof(navigationName));;
Check.NullButNotEmpty(navigationName, nameof(navigationName));

return HasMany(navigationName, FindRelatedEntityType(relatedType, navigationName));
return HasMany(navigationName,
FindRelatedEntityType(relatedType, navigationName),
navigationConfiguration);
}

private CollectionNavigationBuilder HasMany(string navigationName, EntityType relatedEntityType)
private CollectionNavigationBuilder HasMany(
string navigationName,
EntityType relatedEntityType,
Action<NavigationBuilder> navigationConfiguration = null)
{
var skipNavigation = navigationName != null ? Builder.Metadata.FindSkipNavigation(navigationName) : null;

Expand All @@ -783,11 +830,19 @@ private CollectionNavigationBuilder HasMany(string navigationName, EntityType re
.IsUnique(false, ConfigurationSource.Explicit);
}

var foreignKey = relationship?.Metadata;
if (navigationConfiguration != null
&& foreignKey?.PrincipalToDependent != null)
{
navigationConfiguration(
new NavigationBuilder(foreignKey.PrincipalToDependent));
}

return new CollectionNavigationBuilder(
Builder.Metadata,
relatedEntityType,
new MemberIdentity(navigationName),
relationship?.Metadata,
foreignKey,
skipNavigation);
}

Expand Down
Loading