diff --git a/src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs b/src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs
index b44240263ed..3c273c8de95 100644
--- a/src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs
+++ b/src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs
@@ -234,6 +234,20 @@ public virtual PropertyBuilder IndexedProperty([NotNull] Type propertyType, [Not
Check.NotNull(propertyType, nameof(propertyType)),
Check.NotEmpty(propertyName, nameof(propertyName)), ConfigurationSource.Explicit).Metadata);
+ ///
+ ///
+ /// Returns an object that can be used to configure an existing navigation property
+ /// from the owned type to its owner. It is an error for the navigation property
+ /// not to exist.
+ ///
+ ///
+ /// The name of the navigation property to be configured.
+ /// An object that can be used to configure the navigation property.
+ public virtual NavigationBuilder Navigation([NotNull] string navigationName)
+ => new NavigationBuilder(
+ DependentEntityType.Builder.Navigation(
+ Check.NotEmpty(navigationName, nameof(navigationName))));
+
///
/// Excludes the given property from the entity type. This method is typically used to remove properties
/// or navigations from the owned entity type that were added by convention.
diff --git a/src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs b/src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs
index cdf7eff8b29..edf2f5d20dd 100644
--- a/src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs
+++ b/src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs
@@ -91,6 +91,23 @@ public virtual PropertyBuilder Property(
Check.NotNull(propertyExpression, nameof(propertyExpression)).GetPropertyAccess(),
ConfigurationSource.Explicit).Metadata));
+ ///
+ ///
+ /// Returns an object that can be used to configure an existing navigation property
+ /// from the owned type to its owner. It is an error for the navigation property
+ /// not to exist.
+ ///
+ ///
+ ///
+ /// A lambda expression representing the navigation property to be configured (
+ /// blog => blog.Posts).
+ ///
+ /// An object that can be used to configure the navigation property.
+ public virtual NavigationBuilder Navigation(
+ [NotNull] Expression> navigationExpression)
+ => new NavigationBuilder(DependentEntityType.Builder.Navigation(
+ Check.NotNull(navigationExpression, nameof(navigationExpression)).GetPropertyAccess()));
+
///
/// Excludes the given property from the entity type. This method is typically used to remove properties
/// or navigations from the owned entity type that were added by convention.
diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs
index dfaec47500b..a9ebbddbaa8 100644
--- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs
+++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs
@@ -226,6 +226,14 @@ public override TestIndexBuilder HasIndex(params string[] propertyNames)
public override TestOwnedNavigationBuilder OwnsOne(string navigationName)
=> new GenericTestOwnedNavigationBuilder(EntityTypeBuilder.OwnsOne(navigationName));
+ public override TestEntityTypeBuilder OwnsOne(
+ string navigationName,
+ Action> buildAction)
+ => Wrap(
+ EntityTypeBuilder.OwnsOne(
+ navigationName,
+ r => buildAction(new GenericTestOwnedNavigationBuilder(r))));
+
public override TestOwnedNavigationBuilder OwnsOne(
Expression> navigationExpression)
=> new GenericTestOwnedNavigationBuilder(EntityTypeBuilder.OwnsOne(navigationExpression));
@@ -241,6 +249,13 @@ public override TestEntityTypeBuilder OwnsOne(
public override TestOwnedNavigationBuilder OwnsMany(string navigationName)
=> new GenericTestOwnedNavigationBuilder(
EntityTypeBuilder.OwnsMany(navigationName));
+ public override TestEntityTypeBuilder OwnsMany(
+ string navigationName,
+ Action> buildAction)
+ => Wrap(
+ EntityTypeBuilder.OwnsMany(
+ navigationName,
+ r => buildAction(new GenericTestOwnedNavigationBuilder(r))));
public override TestOwnedNavigationBuilder OwnsMany(
Expression>> navigationExpression)
@@ -729,6 +744,12 @@ public override TestPropertyBuilder Property(
Expression> propertyExpression)
=> new GenericTestPropertyBuilder(OwnedNavigationBuilder.Property(propertyExpression));
+ public override TestNavigationBuilder Navigation(string navigationName)
+ => new GenericTestNavigationBuilder(OwnedNavigationBuilder.Navigation(navigationName));
+ public override TestNavigationBuilder Navigation(
+ Expression> navigationExpression)
+ => new GenericTestNavigationBuilder(OwnedNavigationBuilder.Navigation(navigationExpression));
+
public override TestOwnedNavigationBuilder Ignore(string propertyName)
=> Wrap(OwnedNavigationBuilder.Ignore(propertyName));
diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs
index 1e0496d07f2..08325877606 100644
--- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs
+++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs
@@ -173,6 +173,14 @@ public override TestIndexBuilder HasIndex(params string[] propertyNames)
public override TestOwnedNavigationBuilder OwnsOne(string navigationName)
=> new NonGenericTestOwnedNavigationBuilder(
EntityTypeBuilder.OwnsOne(typeof(TRelatedEntity), navigationName));
+ public override TestEntityTypeBuilder OwnsOne(
+ string navigationName,
+ Action> buildAction)
+ => Wrap(
+ EntityTypeBuilder.OwnsOne(
+ typeof(TRelatedEntity),
+ navigationName,
+ r => buildAction(new NonGenericTestOwnedNavigationBuilder(r))));
public override TestOwnedNavigationBuilder OwnsOne(
Expression> navigationExpression)
@@ -191,6 +199,14 @@ public override TestEntityTypeBuilder OwnsOne(
public override TestOwnedNavigationBuilder OwnsMany(string navigationName)
=> new NonGenericTestOwnedNavigationBuilder(
EntityTypeBuilder.OwnsMany(typeof(TRelatedEntity), navigationName));
+ public override TestEntityTypeBuilder OwnsMany(
+ string navigationName,
+ Action> buildAction)
+ => Wrap(
+ EntityTypeBuilder.OwnsMany(
+ typeof(TRelatedEntity),
+ navigationName,
+ r => buildAction(new NonGenericTestOwnedNavigationBuilder(r))));
public override TestOwnedNavigationBuilder OwnsMany(
Expression>> navigationExpression)
@@ -407,18 +423,18 @@ public override TestPropertyBuilder HasConversion(ValueConverter conv
protected class NonGenericTestNavigationBuilder : TestNavigationBuilder
{
- public NonGenericTestNavigationBuilder(NavigationBuilder navigationIdentityBuilder)
+ public NonGenericTestNavigationBuilder(NavigationBuilder navigationBuilder)
{
- NavigationIdentityBuilder = navigationIdentityBuilder;
+ NavigationBuilder = navigationBuilder;
}
- private NavigationBuilder NavigationIdentityBuilder { get; }
+ private NavigationBuilder NavigationBuilder { get; }
public override TestNavigationBuilder HasAnnotation(string annotation, object value)
- => new NonGenericTestNavigationBuilder(NavigationIdentityBuilder.HasAnnotation(annotation, value));
+ => new NonGenericTestNavigationBuilder(NavigationBuilder.HasAnnotation(annotation, value));
public override TestNavigationBuilder UsePropertyAccessMode(PropertyAccessMode propertyAccessMode)
- => new NonGenericTestNavigationBuilder(NavigationIdentityBuilder.UsePropertyAccessMode(propertyAccessMode));
+ => new NonGenericTestNavigationBuilder(NavigationBuilder.UsePropertyAccessMode(propertyAccessMode));
}
protected class
@@ -725,6 +741,13 @@ public override TestPropertyBuilder Property(
OwnedNavigationBuilder.Property(propertyInfo.PropertyType, propertyInfo.GetSimpleMemberName()));
}
+ public override TestNavigationBuilder Navigation(string navigationName)
+ => new NonGenericTestNavigationBuilder(OwnedNavigationBuilder.Navigation(navigationName));
+ public override TestNavigationBuilder Navigation(
+ Expression> navigationExpression)
+ => new NonGenericTestNavigationBuilder(
+ OwnedNavigationBuilder.Navigation(navigationExpression.GetPropertyAccess().GetSimpleMemberName()));
+
public override TestOwnedNavigationBuilder Ignore(string propertyName)
=> Wrap(OwnedNavigationBuilder.Ignore(propertyName));
diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs
index 95f9105e6ec..e135b25521d 100644
--- a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs
+++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs
@@ -208,6 +208,11 @@ public abstract TestEntityTypeBuilder Ignore(
public abstract TestOwnedNavigationBuilder OwnsOne(string navigationName)
where TRelatedEntity : class;
+ public abstract TestEntityTypeBuilder OwnsOne(
+ string navigationName,
+ Action> buildAction)
+ where TRelatedEntity : class;
+
public abstract TestOwnedNavigationBuilder OwnsOne(
Expression> navigationExpression)
where TRelatedEntity : class;
@@ -219,6 +224,11 @@ public abstract TestEntityTypeBuilder OwnsOne(
public abstract TestOwnedNavigationBuilder OwnsMany(string navigationName)
where TRelatedEntity : class;
+ public abstract TestEntityTypeBuilder OwnsMany(
+ string navigationName,
+ Action> buildAction)
+ where TRelatedEntity : class;
+
public abstract TestOwnedNavigationBuilder OwnsMany(
Expression>> navigationExpression)
where TRelatedEntity : class;
@@ -521,6 +531,10 @@ public abstract TestOwnedNavigationBuilder HasAnnotat
public abstract TestPropertyBuilder Property(
Expression> propertyExpression);
+ public abstract TestNavigationBuilder Navigation(string navigationName);
+ public abstract TestNavigationBuilder Navigation(
+ Expression> navigationExpression);
+
public abstract TestOwnedNavigationBuilder Ignore(string propertyName);
public abstract TestOwnedNavigationBuilder Ignore(
diff --git a/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs b/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs
index 693a223d46f..00766257b37 100644
--- a/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs
+++ b/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs
@@ -1331,77 +1331,111 @@ public virtual void Inheritance_where_base_has_multiple_owned_types_works()
}
[ConditionalFact]
- public virtual void Principal_end_of_navigations_to_OneToOne_Owned_types_can_set_access_mode_using_expressions()
+ public virtual void Navigations_on_OwnsOne_Owned_types_can_set_access_mode_using_expressions()
{
var modelBuilder = CreateModelBuilder();
var model = modelBuilder.Model;
modelBuilder.Entity()
- .OwnsOne(e => e.OwnedDependent)
- .WithOwner(e => e.OneToOneOwner);
+ .OwnsOne(
+ e => e.OwnedDependent,
+ a =>
+ {
+ a.WithOwner(owned => owned.OneToOneOwner);
+ a.Navigation(owned => owned.OneToOneOwner)
+ .UsePropertyAccessMode(PropertyAccessMode.Property);
+ });
modelBuilder.Entity()
.Navigation(e => e.OwnedDependent)
.UsePropertyAccessMode(PropertyAccessMode.Field);
var principal = (IEntityType)model.FindEntityType(typeof(OneToOneNavPrincipalOwner));
+ var dependent = (IEntityType)model.FindEntityType(typeof(OwnedNavDependent));
Assert.Equal(PropertyAccessMode.Field, principal.FindNavigation("OwnedDependent").GetPropertyAccessMode());
+ Assert.Equal(PropertyAccessMode.Property, dependent.FindNavigation("OneToOneOwner").GetPropertyAccessMode());
}
[ConditionalFact]
- public virtual void Principal_end_of_navigations_to_OneToOne_Owned_types_can_set_access_mode_using_navigation_names()
+ public virtual void Navigations_on_OwnsOne_Owned_types_can_set_access_mode_using_navigation_names()
{
var modelBuilder = CreateModelBuilder();
var model = modelBuilder.Model;
modelBuilder.Entity()
- .OwnsOne("OwnedDependent")
- .WithOwner("OneToOneOwner");
+ .OwnsOne(
+ "OwnedDependent",
+ a =>
+ {
+ a.WithOwner("OneToOneOwner");
+ a.Navigation("OneToOneOwner")
+ .UsePropertyAccessMode(PropertyAccessMode.Property);
+ });
modelBuilder.Entity()
.Navigation("OwnedDependent")
.UsePropertyAccessMode(PropertyAccessMode.Field);
var principal = (IEntityType)model.FindEntityType(typeof(OneToOneNavPrincipalOwner));
+ var dependent = (IEntityType)model.FindEntityType(typeof(OwnedNavDependent));
Assert.Equal(PropertyAccessMode.Field, principal.FindNavigation("OwnedDependent").GetPropertyAccessMode());
+ Assert.Equal(PropertyAccessMode.Property, dependent.FindNavigation("OneToOneOwner").GetPropertyAccessMode());
}
[ConditionalFact]
- public virtual void Principal_end_of_navigations_to_OneToMany_Owned_types_can_set_access_mode_using_expressions()
+ public virtual void Navigations_on_OwnsMany_Owned_types_can_set_access_mode_using_expressions()
{
var modelBuilder = CreateModelBuilder();
var model = modelBuilder.Model;
modelBuilder.Entity()
- .OwnsMany(e => e.OwnedDependents);
+ .OwnsMany(
+ e => e.OwnedDependents,
+ a =>
+ {
+ a.WithOwner(owned => owned.OneToManyOwner);
+ a.Navigation(owned => owned.OneToManyOwner)
+ .UsePropertyAccessMode(PropertyAccessMode.Property);
+ });
modelBuilder.Entity()
.Navigation(e => e.OwnedDependents)
.UsePropertyAccessMode(PropertyAccessMode.Field);
var principal = (IEntityType)model.FindEntityType(typeof(OneToManyNavPrincipalOwner));
+ var dependent = (IEntityType)model.FindEntityType(typeof(OwnedOneToManyNavDependent));
Assert.Equal(PropertyAccessMode.Field, principal.FindNavigation("OwnedDependents").GetPropertyAccessMode());
+ Assert.Equal(PropertyAccessMode.Property, dependent.FindNavigation("OneToManyOwner").GetPropertyAccessMode());
}
[ConditionalFact]
- public virtual void Principal_end_of_navigations_to_OneToMany_Owned_types_can_set_access_mode_using_navigation_names()
+ public virtual void Navigations_on_OwnsMany_Owned_types_can_set_access_mode_using_navigation_names()
{
var modelBuilder = CreateModelBuilder();
var model = modelBuilder.Model;
modelBuilder.Entity()
- .OwnsMany("OwnedDependents");
+ .OwnsMany(
+ "OwnedDependents",
+ a =>
+ {
+ a.WithOwner("OneToManyOwner");
+ a.Navigation("OneToManyOwner")
+ .UsePropertyAccessMode(PropertyAccessMode.Property);
+ });
modelBuilder.Entity()
.Navigation("OwnedDependents")
.UsePropertyAccessMode(PropertyAccessMode.Field);
var principal = (IEntityType)model.FindEntityType(typeof(OneToManyNavPrincipalOwner));
+ var dependent = (IEntityType)model.FindEntityType(typeof(OwnedOneToManyNavDependent));
Assert.Equal(PropertyAccessMode.Field, principal.FindNavigation("OwnedDependents").GetPropertyAccessMode());
+ Assert.Equal(PropertyAccessMode.Property, dependent.FindNavigation("OneToManyOwner").GetPropertyAccessMode());
}
}
}