diff --git a/src/EFCore.Cosmos/ValueGeneration/Internal/IdValueGenerator.cs b/src/EFCore.Cosmos/ValueGeneration/Internal/IdValueGenerator.cs
index 7177dc8b833..26a4dc2e855 100644
--- a/src/EFCore.Cosmos/ValueGeneration/Internal/IdValueGenerator.cs
+++ b/src/EFCore.Cosmos/ValueGeneration/Internal/IdValueGenerator.cs
@@ -61,7 +61,7 @@ protected override object NextValue(EntityEntry entry)
continue;
}
- var value = entry.Property(property.Name).CurrentValue;
+ var value = entry.Property(property).CurrentValue;
var converter = property.GetTypeMapping().Converter;
if (converter != null)
diff --git a/src/EFCore/ChangeTracking/CollectionEntry.cs b/src/EFCore/ChangeTracking/CollectionEntry.cs
index aed757475d1..4155b069830 100644
--- a/src/EFCore/ChangeTracking/CollectionEntry.cs
+++ b/src/EFCore/ChangeTracking/CollectionEntry.cs
@@ -47,8 +47,8 @@ public CollectionEntry(InternalEntityEntry internalEntry, string name)
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
[EntityFrameworkInternal]
- public CollectionEntry(InternalEntityEntry internalEntry, INavigation navigation)
- : base(internalEntry, navigation)
+ public CollectionEntry(InternalEntityEntry internalEntry, INavigationBase navigationBase)
+ : base(internalEntry, navigationBase, collection: true)
{
LocalDetectChanges();
}
diff --git a/src/EFCore/ChangeTracking/CollectionEntry`.cs b/src/EFCore/ChangeTracking/CollectionEntry`.cs
index 84463fb3ae4..b848c0f3764 100644
--- a/src/EFCore/ChangeTracking/CollectionEntry`.cs
+++ b/src/EFCore/ChangeTracking/CollectionEntry`.cs
@@ -45,8 +45,8 @@ public CollectionEntry(InternalEntityEntry internalEntry, string name)
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
[EntityFrameworkInternal]
- public CollectionEntry(InternalEntityEntry internalEntry, INavigation navigation)
- : base(internalEntry, navigation)
+ public CollectionEntry(InternalEntityEntry internalEntry, INavigationBase navigationBase)
+ : base(internalEntry, navigationBase)
{
}
diff --git a/src/EFCore/ChangeTracking/EntityEntry.cs b/src/EFCore/ChangeTracking/EntityEntry.cs
index b0d74f76eee..3c500ddce15 100644
--- a/src/EFCore/ChangeTracking/EntityEntry.cs
+++ b/src/EFCore/ChangeTracking/EntityEntry.cs
@@ -129,15 +129,39 @@ public virtual DbContext Context
public virtual IEntityType Metadata
=> InternalEntry.EntityType;
+ ///
+ /// Provides access to change tracking information and operations for a given property or navigation of this entity.
+ ///
+ ///
+ /// See Accessing tracked entities in EF Core for more information and
+ /// examples.
+ ///
+ /// The property or navigation to access information and operations for.
+ /// An object that exposes change tracking information and operations for the given property.
+ public virtual MemberEntry Member(IPropertyBase propertyBase)
+ {
+ Check.NotNull(propertyBase, nameof(propertyBase));
+
+ return propertyBase switch
+ {
+ IProperty property => new PropertyEntry(InternalEntry, property),
+ INavigationBase navigation => navigation.IsCollection
+ ? new CollectionEntry(InternalEntry, navigation)
+ : new ReferenceEntry(InternalEntry, (INavigation)navigation),
+ _ => throw new InvalidOperationException(
+ CoreStrings.PropertyNotFound(propertyBase.Name, InternalEntry.EntityType.DisplayName()))
+ };
+ }
+
///
/// Provides access to change tracking information and operations for a given
- /// property or navigation property of this entity.
+ /// property or navigation of this entity.
///
///
/// See Accessing tracked entities in EF Core for more information and
/// examples.
///
- /// The property to access information and operations for.
+ /// The property or navigation to access information and operations for.
/// An object that exposes change tracking information and operations for the given property.
public virtual MemberEntry Member(string propertyName)
{
@@ -163,9 +187,8 @@ public virtual MemberEntry Member(string propertyName)
}
///
- /// Provides access to change tracking information and operations for all
- /// properties and navigation properties of this entity.
- ///
+ /// Provides access to change tracking information and operations for all properties and navigations of this entity.
+ /// -
///
/// See Accessing tracked entities in EF Core for more information and
/// examples.
@@ -174,15 +197,33 @@ public virtual IEnumerable Members
=> Properties.Cast().Concat(Navigations);
///
- /// Provides access to change tracking information and operations for a given
- /// navigation property of this entity.
+ /// Provides access to change tracking information and operations for a given navigation of this entity.
///
///
/// See Accessing tracked entities in EF Core
/// and Changing foreign keys and navigations
/// for more information and examples.
///
- /// The property to access information and operations for.
+ /// The navigation to access information and operations for.
+ /// An object that exposes change tracking information and operations for the given property.
+ public virtual NavigationEntry Navigation(INavigationBase navigationBase)
+ {
+ Check.NotNull(navigationBase, nameof(navigationBase));
+
+ return navigationBase.IsCollection
+ ? new CollectionEntry(InternalEntry, navigationBase)
+ : new ReferenceEntry(InternalEntry, (INavigation)navigationBase);
+ }
+
+ ///
+ /// Provides access to change tracking information and operations for a given navigation of this entity.
+ ///
+ ///
+ /// See Accessing tracked entities in EF Core
+ /// and Changing foreign keys and navigations
+ /// for more information and examples.
+ ///
+ /// The navigation to access information and operations for.
/// An object that exposes change tracking information and operations for the given property.
public virtual NavigationEntry Navigation(string propertyName)
{
@@ -234,8 +275,23 @@ public virtual IEnumerable Navigations
}
///
- /// Provides access to change tracking information and operations for a given
- /// property of this entity.
+ /// Provides access to change tracking information and operations for a given property of this entity.
+ ///
+ ///
+ /// See Accessing tracked entities in EF Core for more information and
+ /// examples.
+ ///
+ /// The property to access information and operations for.
+ /// An object that exposes change tracking information and operations for the given property.
+ public virtual PropertyEntry Property(IProperty property)
+ {
+ Check.NotNull(property, nameof(property));
+
+ return new PropertyEntry(InternalEntry, property);
+ }
+
+ ///
+ /// Provides access to change tracking information and operations for a given property of this entity.
///
///
/// See Accessing tracked entities in EF Core for more information and
@@ -263,17 +319,36 @@ public virtual IEnumerable Properties
///
/// Provides access to change tracking and loading information for a reference (i.e. non-collection)
- /// navigation property that associates this entity to another entity.
+ /// navigation that associates this entity to another entity.
///
///
/// See Accessing tracked entities in EF Core
/// and Changing foreign keys and navigations
/// for more information and examples.
///
- /// The name of the navigation property.
+ /// The reference navigation.
///
- /// An object that exposes change tracking information and operations for the
- /// given navigation property.
+ /// An object that exposes change tracking information and operations for the given navigation.
+ ///
+ public virtual ReferenceEntry Reference(INavigationBase navigation)
+ {
+ Check.NotNull(navigation, nameof(navigation));
+
+ return new ReferenceEntry(InternalEntry, (INavigation)navigation);
+ }
+
+ ///
+ /// Provides access to change tracking and loading information for a reference (i.e. non-collection)
+ /// navigation that associates this entity to another entity.
+ ///
+ ///
+ /// See Accessing tracked entities in EF Core
+ /// and Changing foreign keys and navigations
+ /// for more information and examples.
+ ///
+ /// The name of the navigation.
+ ///
+ /// An object that exposes change tracking information and operations for the given navigation.
///
public virtual ReferenceEntry Reference(string propertyName)
{
@@ -297,17 +372,37 @@ public virtual IEnumerable References
///
/// Provides access to change tracking and loading information for a collection
- /// navigation property that associates this entity to a collection of another entities.
+ /// navigation that associates this entity to a collection of another entities.
+ ///
+ ///
+ /// See Accessing tracked entities in EF Core
+ /// and Changing foreign keys and navigations
+ /// for more information and examples.
+ ///
+ /// The collection navigation.
+ ///
+ /// An object that exposes change tracking information and operations for the given navigation.
+ ///
+ public virtual CollectionEntry Collection(INavigationBase navigation)
+ {
+ Check.NotNull(navigation, nameof(navigation));
+
+ return new CollectionEntry(InternalEntry, navigation);
+ }
+
+ ///
+ /// Provides access to change tracking and loading information for a collection
+ /// navigation that associates this entity to a collection of another entities.
///
///
/// See Accessing tracked entities in EF Core
/// and Changing foreign keys and navigations
/// for more information and examples.
///
- /// The name of the navigation property.
+ /// The name of the navigation.
///
/// An object that exposes change tracking information and operations for the
- /// given navigation property.
+ /// given navigation.
///
public virtual CollectionEntry Collection(string propertyName)
{
diff --git a/src/EFCore/ChangeTracking/EntityEntry`.cs b/src/EFCore/ChangeTracking/EntityEntry`.cs
index a5e1d2dd814..050be2e5439 100644
--- a/src/EFCore/ChangeTracking/EntityEntry`.cs
+++ b/src/EFCore/ChangeTracking/EntityEntry`.cs
@@ -41,16 +41,14 @@ public EntityEntry(InternalEntityEntry internalEntry)
=> (TEntity)base.Entity;
///
- /// Provides access to change tracking information and operations for a given
- /// property of this entity.
+ /// Provides access to change tracking information and operations for a given property of this entity.
///
///
/// See Accessing tracked entities in EF Core for more information and
/// examples.
///
///
- /// A lambda expression representing the property to access information and operations for
- /// (t => t.Property1).
+ /// A lambda expression representing the property to access information and operations for.
///
/// An object that exposes change tracking information and operations for the given property.
public virtual PropertyEntry Property(
@@ -71,12 +69,10 @@ public virtual PropertyEntry Property(
/// for more information and examples.
///
///
- /// A lambda expression representing the property to access information and operations for
- /// (t => t.Property1).
+ /// A lambda expression representing the reference navigation to access information and operations for.
///
///
- /// An object that exposes change tracking information and operations for the
- /// given navigation property.
+ /// An object that exposes change tracking information and operations for the given navigation property.
///
public virtual ReferenceEntry Reference(
Expression> propertyExpression)
@@ -97,12 +93,10 @@ public virtual ReferenceEntry Reference(
/// for more information and examples.
///
///
- /// A lambda expression representing the property to access information and operations for
- /// (t => t.Property1).
+ /// A lambda expression representing the collection navigation to access information and operations for.
///
///
- /// An object that exposes change tracking information and operations for the
- /// given navigation property.
+ /// An object that exposes change tracking information and operations for the given navigation property.
///
public virtual CollectionEntry Collection(
Expression>> propertyExpression)
@@ -113,9 +107,70 @@ public virtual CollectionEntry Collection(
return new CollectionEntry(InternalEntry, propertyExpression.GetMemberAccess().GetSimpleMemberName());
}
+ ///
+ /// Provides access to change tracking information and operations for a given property of this entity.
+ ///
+ ///
+ /// See Accessing tracked entities in EF Core for more information and
+ /// examples.
+ ///
+ /// The type of the property.
+ /// The property to access information and operations for.
+ /// An object that exposes change tracking information and operations for the given property.
+ public virtual PropertyEntry Property(IProperty property)
+ {
+ Check.NotNull(property, nameof(property));
+
+ ValidateType(property);
+
+ return new PropertyEntry(InternalEntry, property);
+ }
+
///
/// Provides access to change tracking and loading information for a reference (i.e. non-collection)
- /// navigation property that associates this entity to another entity.
+ /// navigation that associates this entity to another entity.
+ ///
+ ///
+ /// See Accessing tracked entities in EF Core
+ /// and Changing foreign keys and navigations
+ /// for more information and examples.
+ ///
+ /// The reference navigation.
+ ///
+ /// An object that exposes change tracking information and operations for the given navigation property.
+ ///
+ public virtual ReferenceEntry Reference(INavigationBase navigation)
+ where TProperty : class
+ {
+ Check.NotNull(navigation, nameof(navigation));
+
+ return new ReferenceEntry(InternalEntry, (INavigation)navigation);
+ }
+
+ ///
+ /// Provides access to change tracking and loading information for a collection
+ /// navigation property that associates this entity to a collection of another entities.
+ ///
+ ///
+ /// See Accessing tracked entities in EF Core
+ /// and Changing foreign keys and navigations
+ /// for more information and examples.
+ ///
+ /// The collection navigation.
+ ///
+ /// An object that exposes change tracking information and operations for the given navigation property.
+ ///
+ public virtual CollectionEntry Collection(INavigationBase navigation)
+ where TProperty : class
+ {
+ Check.NotNull(navigation, nameof(navigation));
+
+ return new CollectionEntry(InternalEntry, navigation);
+ }
+
+ ///
+ /// Provides access to change tracking and loading information for a reference (i.e. non-collection)
+ /// navigation that associates this entity to another entity.
///
///
/// See Accessing tracked entities in EF Core
@@ -124,8 +179,7 @@ public virtual CollectionEntry Collection(
///
/// The name of the navigation property.
///
- /// An object that exposes change tracking information and operations for the
- /// given navigation property.
+ /// An object that exposes change tracking information and operations for the given navigation property.
///
public virtual ReferenceEntry Reference(string propertyName)
where TProperty : class
@@ -146,8 +200,7 @@ public virtual ReferenceEntry Reference(string pr
///
/// The name of the navigation property.
///
- /// An object that exposes change tracking information and operations for the
- /// given navigation property.
+ /// An object that exposes change tracking information and operations for the given navigation property.
///
public virtual CollectionEntry Collection(string propertyName)
where TProperty : class
@@ -158,8 +211,7 @@ public virtual CollectionEntry Collection(string
}
///
- /// Provides access to change tracking information and operations for a given
- /// property of this entity.
+ /// Provides access to change tracking information and operations for a given property of this entity.
///
///
/// See Accessing tracked entities in EF Core for more information and
@@ -168,8 +220,7 @@ public virtual CollectionEntry Collection(string
/// The type of the property.
/// The property to access information and operations for.
/// An object that exposes change tracking information and operations for the given property.
- public virtual PropertyEntry Property(
- string propertyName)
+ public virtual PropertyEntry Property(string propertyName)
{
Check.NotEmpty(propertyName, nameof(propertyName));
diff --git a/src/EFCore/ChangeTracking/NavigationEntry.cs b/src/EFCore/ChangeTracking/NavigationEntry.cs
index eb2dd1ccd6b..de6178f1a26 100644
--- a/src/EFCore/ChangeTracking/NavigationEntry.cs
+++ b/src/EFCore/ChangeTracking/NavigationEntry.cs
@@ -29,7 +29,7 @@ public abstract class NavigationEntry : MemberEntry
///
[EntityFrameworkInternal]
protected NavigationEntry(InternalEntityEntry internalEntry, string name, bool collection)
- : this(internalEntry, GetNavigation(internalEntry, name, collection))
+ : this(internalEntry, GetNavigation(internalEntry, name), collection)
{
}
@@ -40,12 +40,29 @@ protected NavigationEntry(InternalEntityEntry internalEntry, string name, bool c
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
[EntityFrameworkInternal]
- protected NavigationEntry(InternalEntityEntry internalEntry, INavigationBase navigation)
- : base(internalEntry, navigation)
+ protected NavigationEntry(InternalEntityEntry internalEntry, INavigationBase navigationBase, bool collection)
+ : base(internalEntry, navigationBase)
{
+ if (collection
+ && !navigationBase.IsCollection)
+ {
+ throw new InvalidOperationException(
+ CoreStrings.CollectionIsReference(
+ navigationBase.Name, internalEntry.EntityType.DisplayName(),
+ nameof(ChangeTracking.EntityEntry.Collection), nameof(ChangeTracking.EntityEntry.Reference)));
+ }
+
+ if (!collection
+ && navigationBase.IsCollection)
+ {
+ throw new InvalidOperationException(
+ CoreStrings.ReferenceIsCollection(
+ navigationBase.Name, internalEntry.EntityType.DisplayName(),
+ nameof(ChangeTracking.EntityEntry.Reference), nameof(ChangeTracking.EntityEntry.Collection)));
+ }
}
- private static INavigationBase GetNavigation(InternalEntityEntry internalEntry, string name, bool collection)
+ private static INavigationBase GetNavigation(InternalEntityEntry internalEntry, string name)
{
var navigation = (INavigationBase?)internalEntry.EntityType.FindNavigation(name)
?? internalEntry.EntityType.FindSkipNavigation(name);
@@ -64,24 +81,6 @@ private static INavigationBase GetNavigation(InternalEntityEntry internalEntry,
throw new InvalidOperationException(CoreStrings.PropertyNotFound(name, internalEntry.EntityType.DisplayName()));
}
- if (collection
- && !navigation.IsCollection)
- {
- throw new InvalidOperationException(
- CoreStrings.CollectionIsReference(
- name, internalEntry.EntityType.DisplayName(),
- nameof(ChangeTracking.EntityEntry.Collection), nameof(ChangeTracking.EntityEntry.Reference)));
- }
-
- if (!collection
- && navigation.IsCollection)
- {
- throw new InvalidOperationException(
- CoreStrings.ReferenceIsCollection(
- name, internalEntry.EntityType.DisplayName(),
- nameof(ChangeTracking.EntityEntry.Reference), nameof(ChangeTracking.EntityEntry.Collection)));
- }
-
return navigation;
}
diff --git a/src/EFCore/ChangeTracking/ReferenceEntry.cs b/src/EFCore/ChangeTracking/ReferenceEntry.cs
index 30a570b384a..9fbe44d2919 100644
--- a/src/EFCore/ChangeTracking/ReferenceEntry.cs
+++ b/src/EFCore/ChangeTracking/ReferenceEntry.cs
@@ -49,7 +49,7 @@ public ReferenceEntry(InternalEntityEntry internalEntry, string name)
///
[EntityFrameworkInternal]
public ReferenceEntry(InternalEntityEntry internalEntry, INavigation navigation)
- : base(internalEntry, navigation)
+ : base(internalEntry, navigation, collection: false)
{
LocalDetectChanges();
diff --git a/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CustomPartitionKeyIdGenerator.cs b/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CustomPartitionKeyIdGenerator.cs
index 72372423660..530cb38419c 100644
--- a/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CustomPartitionKeyIdGenerator.cs
+++ b/test/EFCore.Cosmos.FunctionalTests/TestUtilities/CustomPartitionKeyIdGenerator.cs
@@ -36,7 +36,7 @@ protected override object NextValue(EntityEntry entry)
continue;
}
- var value = entry.Property(property.Name).CurrentValue;
+ var value = entry.Property(property).CurrentValue;
var converter = property.GetTypeMapping().Converter;
if (converter != null)
diff --git a/test/EFCore.Specification.Tests/BuiltInDataTypesTestBase.cs b/test/EFCore.Specification.Tests/BuiltInDataTypesTestBase.cs
index 269a41b3440..46dd9c8011d 100644
--- a/test/EFCore.Specification.Tests/BuiltInDataTypesTestBase.cs
+++ b/test/EFCore.Specification.Tests/BuiltInDataTypesTestBase.cs
@@ -467,7 +467,7 @@ private void QueryBuiltInDataTypesTest(EntityEntry source)
}
Assert.Equal(
- source.Property(propertyEntry.Metadata.Name).CurrentValue,
+ source.Property(propertyEntry.Metadata).CurrentValue,
propertyEntry.CurrentValue);
}
}
@@ -838,7 +838,7 @@ private void QueryBuiltInNullableDataTypesTest(EntityEntry sou
}
Assert.Equal(
- source.Property(propertyEntry.Metadata.Name).CurrentValue,
+ source.Property(propertyEntry.Metadata).CurrentValue,
propertyEntry.CurrentValue);
}
}
diff --git a/test/EFCore.Specification.Tests/ValueConvertersEndToEndTestBase.cs b/test/EFCore.Specification.Tests/ValueConvertersEndToEndTestBase.cs
index b9aa7d183b4..8a944aed994 100644
--- a/test/EFCore.Specification.Tests/ValueConvertersEndToEndTestBase.cs
+++ b/test/EFCore.Specification.Tests/ValueConvertersEndToEndTestBase.cs
@@ -217,7 +217,7 @@ private static void SetPropertyValues(DbContext context, ConvertingEntity entity
testValues[3] = null;
}
- var propertyEntry = entry.Property(property.Name);
+ var propertyEntry = entry.Property(property);
if (previousValueIndex >= 0
&& property.FindAnnotation("Relational:DefaultValue") == null)
diff --git a/test/EFCore.Tests/ChangeTracking/EntityEntryTest.cs b/test/EFCore.Tests/ChangeTracking/EntityEntryTest.cs
index 1d2ff24d0ba..b5f52b7ab6a 100644
--- a/test/EFCore.Tests/ChangeTracking/EntityEntryTest.cs
+++ b/test/EFCore.Tests/ChangeTracking/EntityEntryTest.cs
@@ -311,6 +311,27 @@ public void Can_get_generic_property_entry_by_name()
Assert.Equal("Monkey", context.Entry(entity).Property("Monkey").Metadata.Name);
}
+ [ConditionalFact]
+ public void Can_get_property_entry_by_IProperty()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Chunky()).Entity;
+ var property = context.Entry(entity).Metadata.FindProperty("Monkey")!;
+
+ Assert.Same(property, context.Entry(entity).Property(property).Metadata);
+ Assert.Same(property, context.Entry((object)entity).Property(property).Metadata);
+ }
+
+ [ConditionalFact]
+ public void Can_get_generic_property_entry_by_IProperty()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Chunky()).Entity;
+ var property = context.Entry(entity).Metadata.FindProperty("Monkey")!;
+
+ Assert.Same(property, context.Entry(entity).Property(property).Metadata);
+ }
+
[ConditionalFact]
public void Throws_when_wrong_generic_type_is_used_while_getting_property_entry_by_name()
{
@@ -404,6 +425,27 @@ public void Can_get_generic_reference_entry_by_lambda()
Assert.Equal("Garcia", context.Entry(entity).Reference(e => e.Garcia).Metadata.Name);
}
+ [ConditionalFact]
+ public void Can_get_reference_entry_by_INavigationBase()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Chunky()).Entity;
+ var navigationBase = (INavigationBase)context.Entry(entity).Metadata.FindNavigation("Garcia")!;
+
+ Assert.Same(navigationBase, context.Entry(entity).Reference(navigationBase).Metadata);
+ Assert.Same(navigationBase, context.Entry((object)entity).Reference(navigationBase).Metadata);
+ }
+
+ [ConditionalFact]
+ public void Can_get_generic_reference_entry_by_INavigationBase()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Chunky()).Entity;
+ var navigationBase = (INavigationBase)context.Entry(entity).Metadata.FindNavigation("Garcia")!;
+
+ Assert.Same(navigationBase, context.Entry(entity).Reference(navigationBase).Metadata);
+ }
+
[ConditionalFact]
public void Throws_when_wrong_reference_name_is_used_while_getting_property_entry_by_name()
{
@@ -461,24 +503,45 @@ public void Throws_when_accessing_collection_as_reference()
CoreStrings.ReferenceIsCollection(
"Monkeys", entity.GetType().Name,
nameof(EntityEntry.Reference), nameof(EntityEntry.Collection)),
- Assert.Throws(() => context.Entry(entity).Reference("Monkeys").Metadata.Name).Message);
+ Assert.Throws(() => context.Entry(entity).Reference("Monkeys")).Message);
+
Assert.Equal(
CoreStrings.ReferenceIsCollection(
"Monkeys", entity.GetType().Name,
nameof(EntityEntry.Reference), nameof(EntityEntry.Collection)),
- Assert.Throws(() => context.Entry((object)entity).Reference("Monkeys").Metadata.Name)
- .Message);
+ Assert.Throws(() => context.Entry((object)entity).Reference("Monkeys")).Message);
+
Assert.Equal(
CoreStrings.ReferenceIsCollection(
"Monkeys", entity.GetType().Name,
nameof(EntityEntry.Reference), nameof(EntityEntry.Collection)),
- Assert.Throws(() => context.Entry(entity).Reference("Monkeys").Metadata.Name)
- .Message);
+ Assert.Throws(() => context.Entry(entity).Reference("Monkeys")).Message);
+
+ Assert.Equal(
+ CoreStrings.ReferenceIsCollection(
+ "Monkeys", entity.GetType().Name,
+ nameof(EntityEntry.Reference), nameof(EntityEntry.Collection)),
+ Assert.Throws(() => context.Entry(entity).Reference(e => e.Monkeys)).Message);
+
+ var navigationBase = context.Entry(entity).Navigation("Monkeys").Metadata;
+
Assert.Equal(
CoreStrings.ReferenceIsCollection(
"Monkeys", entity.GetType().Name,
nameof(EntityEntry.Reference), nameof(EntityEntry.Collection)),
- Assert.Throws(() => context.Entry(entity).Reference(e => e.Monkeys).Metadata.Name).Message);
+ Assert.Throws(() => context.Entry(entity).Reference(navigationBase)).Message);
+
+ Assert.Equal(
+ CoreStrings.ReferenceIsCollection(
+ "Monkeys", entity.GetType().Name,
+ nameof(EntityEntry.Reference), nameof(EntityEntry.Collection)),
+ Assert.Throws(() => context.Entry((object)entity).Reference(navigationBase)).Message);
+
+ Assert.Equal(
+ CoreStrings.ReferenceIsCollection(
+ "Monkeys", entity.GetType().Name,
+ nameof(EntityEntry.Reference), nameof(EntityEntry.Collection)),
+ Assert.Throws(() => context.Entry(entity).Reference(navigationBase)).Message);
}
[ConditionalFact]
@@ -509,6 +572,28 @@ public void Can_get_generic_collection_entry_by_lambda()
Assert.Equal("Monkeys", context.Entry(entity).Collection(e => e.Monkeys).Metadata.Name);
}
+
+ [ConditionalFact]
+ public void Can_get_collection_entry_by_INavigationBase()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Cherry()).Entity;
+ var navigationBase = (INavigationBase)context.Entry(entity).Metadata.FindNavigation("Monkeys")!;
+
+ Assert.Same(navigationBase, context.Entry(entity).Collection(navigationBase).Metadata);
+ Assert.Same(navigationBase, context.Entry((object)entity).Collection(navigationBase).Metadata);
+ }
+
+ [ConditionalFact]
+ public void Can_get_generic_collection_entry_by_INavigationBase()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Cherry()).Entity;
+ var navigationBase = (INavigationBase)context.Entry(entity).Metadata.FindNavigation("Monkeys")!;
+
+ Assert.Same(navigationBase, context.Entry(entity).Collection(navigationBase).Metadata);
+ }
+
[ConditionalFact]
public void Throws_when_wrong_collection_name_is_used_while_getting_property_entry_by_name()
{
@@ -563,19 +648,39 @@ public void Throws_when_accessing_reference_as_collection()
CoreStrings.CollectionIsReference(
"Garcia", entity.GetType().Name,
nameof(EntityEntry.Collection), nameof(EntityEntry.Reference)),
- Assert.Throws(() => context.Entry(entity).Collection("Garcia").Metadata.Name).Message);
+ Assert.Throws(() => context.Entry(entity).Collection("Garcia")).Message);
+
Assert.Equal(
CoreStrings.CollectionIsReference(
"Garcia", entity.GetType().Name,
nameof(EntityEntry.Collection), nameof(EntityEntry.Reference)),
- Assert.Throws(() => context.Entry((object)entity).Collection("Garcia").Metadata.Name)
- .Message);
+ Assert.Throws(() => context.Entry((object)entity).Collection("Garcia")).Message);
+
Assert.Equal(
CoreStrings.CollectionIsReference(
"Garcia", entity.GetType().Name,
nameof(EntityEntry.Collection), nameof(EntityEntry.Reference)),
- Assert.Throws(() => context.Entry(entity).Collection("Garcia").Metadata.Name)
- .Message);
+ Assert.Throws(() => context.Entry(entity).Collection("Garcia")).Message);
+
+ var navigationBase = context.Entry(entity).Navigation("Garcia").Metadata;
+
+ Assert.Equal(
+ CoreStrings.CollectionIsReference(
+ "Garcia", entity.GetType().Name,
+ nameof(EntityEntry.Collection), nameof(EntityEntry.Reference)),
+ Assert.Throws(() => context.Entry(entity).Collection(navigationBase)).Message);
+
+ Assert.Equal(
+ CoreStrings.CollectionIsReference(
+ "Garcia", entity.GetType().Name,
+ nameof(EntityEntry.Collection), nameof(EntityEntry.Reference)),
+ Assert.Throws(() => context.Entry((object)entity).Collection(navigationBase)).Message);
+
+ Assert.Equal(
+ CoreStrings.CollectionIsReference(
+ "Garcia", entity.GetType().Name,
+ nameof(EntityEntry.Collection), nameof(EntityEntry.Reference)),
+ Assert.Throws(() => context.Entry(entity).Collection(navigationBase)).Message);
}
[ConditionalFact]
@@ -637,6 +742,54 @@ public void Can_get_collection_entry_by_name_using_Member()
Assert.IsType(entry);
}
+ [ConditionalFact]
+ public void Can_get_property_entry_by_IPropertyBase_using_Member()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Chunky()).Entity;
+ var propertyBase = (IPropertyBase)context.Entry(entity).Metadata.FindProperty("Monkey")!;
+
+ var entry = context.Entry(entity).Member(propertyBase);
+ Assert.Same(propertyBase, entry.Metadata);
+ Assert.IsType(entry);
+
+ entry = context.Entry((object)entity).Member(propertyBase);
+ Assert.Same(propertyBase, entry.Metadata);
+ Assert.IsType(entry);
+ }
+
+ [ConditionalFact]
+ public void Can_get_reference_entry_by_IPropertyBase_using_Member()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Chunky()).Entity;
+ var propertyBase = (IPropertyBase)context.Entry(entity).Metadata.FindNavigation("Garcia")!;
+
+ var entry = context.Entry(entity).Member(propertyBase);
+ Assert.Same(propertyBase, entry.Metadata);
+ Assert.IsType(entry);
+
+ entry = context.Entry((object)entity).Member(propertyBase);
+ Assert.Same(propertyBase, entry.Metadata);
+ Assert.IsType(entry);
+ }
+
+ [ConditionalFact]
+ public void Can_get_collection_entry_by_IPropertyBase_using_Member()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Cherry()).Entity;
+ var propertyBase = (IPropertyBase)context.Entry(entity).Metadata.FindNavigation("Monkeys")!;
+
+ var entry = context.Entry(entity).Member(propertyBase);
+ Assert.Same(propertyBase, entry.Metadata);
+ Assert.IsType(entry);
+
+ entry = context.Entry((object)entity).Member(propertyBase);
+ Assert.Same(propertyBase, entry.Metadata);
+ Assert.IsType(entry);
+ }
+
[ConditionalFact]
public void Throws_when_wrong_property_name_is_used_while_getting_property_entry_by_name_using_Navigation()
{
@@ -682,6 +835,38 @@ public void Can_get_collection_entry_by_name_using_Navigation()
Assert.IsType(entry);
}
+ [ConditionalFact]
+ public void Can_get_reference_entry_by_INavigationBase_using_Navigation()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Chunky()).Entity;
+ var navigationBase = (INavigationBase)context.Entry(entity).Metadata.FindNavigation("Garcia")!;
+
+ var entry = context.Entry(entity).Navigation(navigationBase);
+ Assert.Same(navigationBase, entry.Metadata);
+ Assert.IsType(entry);
+
+ entry = context.Entry((object)entity).Navigation(navigationBase);
+ Assert.Same(navigationBase, entry.Metadata);
+ Assert.IsType(entry);
+ }
+
+ [ConditionalFact]
+ public void Can_get_collection_entry_by_INavigationBase_using_Navigation()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Cherry()).Entity;
+ var navigationBase = (INavigationBase)context.Entry(entity).Metadata.FindNavigation("Monkeys")!;
+
+ var entry = context.Entry(entity).Navigation(navigationBase);
+ Assert.Same(navigationBase, entry.Metadata);
+ Assert.IsType(entry);
+
+ entry = context.Entry((object)entity).Navigation(navigationBase);
+ Assert.Same(navigationBase, entry.Metadata);
+ Assert.IsType(entry);
+ }
+
[ConditionalFact]
public void Throws_when_accessing_property_as_navigation()
{
diff --git a/test/EFCore.Tests/ChangeTracking/SkipMemberEntryTest.cs b/test/EFCore.Tests/ChangeTracking/SkipMemberEntryTest.cs
index 046a2af1b58..0c57d77ae67 100644
--- a/test/EFCore.Tests/ChangeTracking/SkipMemberEntryTest.cs
+++ b/test/EFCore.Tests/ChangeTracking/SkipMemberEntryTest.cs
@@ -12,9 +12,8 @@ public void Can_get_back_reference_collection()
{
using var context = new FreezerContext();
var entity = new Cherry();
- context.Add(entity);
- var entityEntry = context.Entry(entity);
+ var entityEntry = context.Add(entity);
Assert.Same(entityEntry.Entity, entityEntry.Member("Chunkies").EntityEntry.Entity);
}
@@ -23,9 +22,9 @@ public void Can_get_metadata_collection()
{
using var context = new FreezerContext();
var entity = new Cherry();
- context.Add(entity);
- Assert.Equal("Chunkies", context.Entry(entity).Member("Chunkies").Metadata.Name);
+ var entityEntry = context.Add(entity);
+ Assert.Equal("Chunkies", entityEntry.Member("Chunkies").Metadata.Name);
}
[ConditionalFact]
@@ -58,6 +57,69 @@ public void Can_get_and_set_current_value_collection()
Assert.Null(collection.CurrentValue);
}
+ [ConditionalFact]
+ public void Can_get_skip_collection_entry_by_name_using_Member()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Cherry()).Entity;
+
+ var entry = context.Entry(entity).Member("Chunkies");
+ Assert.Equal("Chunkies", entry.Metadata.Name);
+ Assert.IsType(entry);
+
+ entry = context.Entry((object)entity).Member("Chunkies");
+ Assert.Equal("Chunkies", entry.Metadata.Name);
+ Assert.IsType(entry);
+ }
+
+ [ConditionalFact]
+ public void Can_get_skip_collection_entry_by_IPropertyBase_using_Member()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Cherry()).Entity;
+ var propertyBase = (IPropertyBase)context.Entry(entity).Metadata.FindSkipNavigation("Chunkies")!;
+
+ var entry = context.Entry(entity).Member(propertyBase);
+ Assert.Same(propertyBase, entry.Metadata);
+ Assert.IsType(entry);
+
+ entry = context.Entry((object)entity).Member(propertyBase);
+ Assert.Same(propertyBase, entry.Metadata);
+ Assert.IsType(entry);
+ }
+
+
+ [ConditionalFact]
+ public void Can_get_skip_collection_entry_by_name_using_Collection()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Cherry()).Entity;
+
+ var entry = context.Entry(entity).Collection("Chunkies");
+ Assert.Equal("Chunkies", entry.Metadata.Name);
+ Assert.IsType(entry);
+
+ entry = context.Entry((object)entity).Collection("Chunkies");
+ Assert.Equal("Chunkies", entry.Metadata.Name);
+ Assert.IsType(entry);
+ }
+
+ [ConditionalFact]
+ public void Can_get_skip_collection_entry_by_INavigationBase_using_Collection()
+ {
+ using var context = new FreezerContext();
+ var entity = context.Add(new Cherry()).Entity;
+ var navigationBase = (INavigationBase)context.Entry(entity).Metadata.FindSkipNavigation("Chunkies")!;
+
+ var entry = context.Entry(entity).Collection(navigationBase);
+ Assert.Same(navigationBase, entry.Metadata);
+ Assert.IsType(entry);
+
+ entry = context.Entry((object)entity).Collection(navigationBase);
+ Assert.Same(navigationBase, entry.Metadata);
+ Assert.IsType(entry);
+ }
+
private class Chunky
{
public int Id { get; set; }
diff --git a/test/EFCore.Tests/ChangeTracking/TrackGraphTestBase.cs b/test/EFCore.Tests/ChangeTracking/TrackGraphTestBase.cs
index 07815e83aa1..308a430ee64 100644
--- a/test/EFCore.Tests/ChangeTracking/TrackGraphTestBase.cs
+++ b/test/EFCore.Tests/ChangeTracking/TrackGraphTestBase.cs
@@ -253,9 +253,9 @@ public void Can_attach_parent_with_owned_dependent(bool useAttach, bool setPrinc
Assert.Equal(expectedDependentState, dependentEntry2b.State);
Assert.Equal(1, sweet.Id);
- Assert.Equal(1, dependentEntry.Property(dependentEntry.Metadata.FindPrimaryKey().Properties[0].Name).CurrentValue);
- Assert.Equal(1, dependentEntry2a.Property(dependentEntry2a.Metadata.FindPrimaryKey().Properties[0].Name).CurrentValue);
- Assert.Equal(1, dependentEntry2b.Property(dependentEntry2b.Metadata.FindPrimaryKey().Properties[0].Name).CurrentValue);
+ Assert.Equal(1, dependentEntry.Property(dependentEntry.Metadata.FindPrimaryKey().Properties[0]).CurrentValue);
+ Assert.Equal(1, dependentEntry2a.Property(dependentEntry2a.Metadata.FindPrimaryKey().Properties[0]).CurrentValue);
+ Assert.Equal(1, dependentEntry2b.Property(dependentEntry2b.Metadata.FindPrimaryKey().Properties[0]).CurrentValue);
}
[ConditionalTheory]
@@ -318,9 +318,9 @@ public void Can_attach_owned_dependent_with_reference_to_parent(bool useAttach,
Assert.Equal(expectedDependentState, dependentEntry2b.State);
Assert.Equal(1, dreams.Sweet.Id);
- Assert.Equal(1, dependentEntry.Property(dependentEntry.Metadata.FindPrimaryKey().Properties[0].Name).CurrentValue);
- Assert.Equal(1, dependentEntry2a.Property(dependentEntry2a.Metadata.FindPrimaryKey().Properties[0].Name).CurrentValue);
- Assert.Equal(1, dependentEntry2b.Property(dependentEntry2b.Metadata.FindPrimaryKey().Properties[0].Name).CurrentValue);
+ Assert.Equal(1, dependentEntry.Property(dependentEntry.Metadata.FindPrimaryKey().Properties[0]).CurrentValue);
+ Assert.Equal(1, dependentEntry2a.Property(dependentEntry2a.Metadata.FindPrimaryKey().Properties[0]).CurrentValue);
+ Assert.Equal(1, dependentEntry2b.Property(dependentEntry2b.Metadata.FindPrimaryKey().Properties[0]).CurrentValue);
}
[ConditionalFact]
@@ -695,9 +695,9 @@ public void Can_add_owned_dependent_with_reference_to_parent(bool useAdd, bool s
Assert.Equal(expectedDependentState, dependentEntry2b.State);
Assert.Equal(1, dreams.Sweet.Id);
- Assert.Equal(1, dependentEntry.Property(dependentEntry.Metadata.FindPrimaryKey().Properties[0].Name).CurrentValue);
- Assert.Equal(1, dependentEntry2a.Property(dependentEntry2a.Metadata.FindPrimaryKey().Properties[0].Name).CurrentValue);
- Assert.Equal(1, dependentEntry2b.Property(dependentEntry2b.Metadata.FindPrimaryKey().Properties[0].Name).CurrentValue);
+ Assert.Equal(1, dependentEntry.Property(dependentEntry.Metadata.FindPrimaryKey().Properties[0]).CurrentValue);
+ Assert.Equal(1, dependentEntry2a.Property(dependentEntry2a.Metadata.FindPrimaryKey().Properties[0]).CurrentValue);
+ Assert.Equal(1, dependentEntry2b.Property(dependentEntry2b.Metadata.FindPrimaryKey().Properties[0]).CurrentValue);
}
[ConditionalTheory] // Issue #12590