Skip to content

Commit e44c946

Browse files
committed
Refactor InternalEntityEntry
Part of #31237
1 parent 8a8e758 commit e44c946

File tree

221 files changed

+7937
-7362
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

221 files changed

+7937
-7362
lines changed

.github/copilot-instructions.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,9 @@ If you are not sure, do not guess, just tell that you don't know or ask clarifyi
8686

8787
- Follow the existing test patterns in the corresponding test projects
8888
- Create both unit tests and functional tests where appropriate
89-
- Add or modify `SQL` and `C#` baselines for tests when necessary
90-
- When running the tests specify the test project and let it be rebuilt.
89+
- Fix `SQL` and `C#` baselines for tests when necessary by setting the `EF_TEST_REWRITE_BASELINES` env var to `1`
90+
- Before building or running the tests execute `restore.cmd` or `restore.sh` and `activate.ps1` or `activate.sh` to set up the environment
91+
- When running the tests specify the test project and let it be rebuilt by not adding `--no-build`
9192

9293
## Documentation
9394

src/EFCore.Design/Scaffolding/Internal/CSharpRuntimeModelCodeGenerator.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
77
using Microsoft.EntityFrameworkCore.Design.Internal;
88
using Microsoft.EntityFrameworkCore.Internal;
9-
using Microsoft.EntityFrameworkCore.Metadata;
109
using Microsoft.EntityFrameworkCore.Metadata.Internal;
1110
using Microsoft.EntityFrameworkCore.Query.Internal;
1211

@@ -1498,8 +1497,10 @@ private void
14981497
var variableName = parameters.TargetName;
14991498
var mainBuilder = parameters.MainBuilder;
15001499
var unsafeAccessors = new HashSet<string>();
1500+
var isOnComplexCollection = property.DeclaringType is IReadOnlyComplexType complexType && complexType.ComplexProperty.IsCollection;
15011501

15021502
if (!property.IsShadowProperty()
1503+
&& !isOnComplexCollection
15031504
&& property is not IServiceProperty) // Service properties don't use property accessors
15041505
{
15051506
ClrPropertyGetterFactory.Instance.Create(
@@ -1559,7 +1560,8 @@ private void
15591560
.DecrementIndent();
15601561
}
15611562

1562-
if (property is not IServiceProperty)
1563+
if (property is not IServiceProperty
1564+
&& !isOnComplexCollection)
15631565
{
15641566
PropertyAccessorsFactory.Instance.Create(
15651567
property,
@@ -2783,6 +2785,21 @@ private void CreateAnnotations(
27832785
mainBuilder.AppendLine(";");
27842786
}
27852787

2788+
foreach (var navigation in entityType.GetSkipNavigations())
2789+
{
2790+
var variableName = _code.Identifier(navigation.Name, navigation, parameters.ScopeObjects, capitalize: false);
2791+
2792+
mainBuilder
2793+
.Append($"var {variableName} = ")
2794+
.Append($"{parameters.TargetName}.FindSkipNavigation({_code.Literal(navigation.Name)})");
2795+
if (nullable)
2796+
{
2797+
mainBuilder.Append("!");
2798+
}
2799+
2800+
mainBuilder.AppendLine(";");
2801+
}
2802+
27862803
var runtimeType = (IRuntimeEntityType)entityType;
27872804
var unsafeAccessors = new HashSet<string>();
27882805

@@ -2866,6 +2883,7 @@ private void CreateAnnotations(
28662883
.Append("propertyCount: ").Append(_code.Literal(counts.PropertyCount)).AppendLine(",")
28672884
.Append("navigationCount: ").Append(_code.Literal(counts.NavigationCount)).AppendLine(",")
28682885
.Append("complexPropertyCount: ").Append(_code.Literal(counts.ComplexPropertyCount)).AppendLine(",")
2886+
.Append("complexCollectionCount: ").Append(_code.Literal(counts.ComplexCollectionCount)).AppendLine(",")
28692887
.Append("originalValueCount: ").Append(_code.Literal(counts.OriginalValueCount)).AppendLine(",")
28702888
.Append("shadowCount: ").Append(_code.Literal(counts.ShadowCount)).AppendLine(",")
28712889
.Append("relationshipCount: ").Append(_code.Literal(counts.RelationshipCount)).AppendLine(",")

src/EFCore.Relational/Metadata/Internal/RelationalModel.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.Reflection.Metadata;
54
using System.Text;
6-
using System.Text.Json;
75

86
namespace Microsoft.EntityFrameworkCore.Metadata.Internal;
97

src/EFCore/ChangeTracking/CollectionEntry.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ public override bool IsModified
109109

110110
if (Metadata is ISkipNavigation skipNavigation)
111111
{
112-
if (InternalEntry.EntityState != EntityState.Unchanged
113-
&& InternalEntry.EntityState != EntityState.Detached)
112+
if (InternalEntityEntry.EntityState != EntityState.Unchanged
113+
&& InternalEntityEntry.EntityState != EntityState.Detached)
114114
{
115115
return true;
116116
}
@@ -231,7 +231,7 @@ public override void Load(LoadOptions options)
231231

232232
if (!IsLoaded)
233233
{
234-
TargetLoader.Load(InternalEntry, options);
234+
TargetLoader.Load(InternalEntityEntry, options);
235235
}
236236
}
237237

@@ -279,7 +279,7 @@ public override Task LoadAsync(LoadOptions options, CancellationToken cancellati
279279

280280
return IsLoaded
281281
? Task.CompletedTask
282-
: TargetLoader.LoadAsync(InternalEntry, options, cancellationToken);
282+
: TargetLoader.LoadAsync(InternalEntityEntry, options, cancellationToken);
283283
}
284284

285285
/// <summary>
@@ -300,11 +300,11 @@ public override IQueryable Query()
300300
{
301301
EnsureInitialized();
302302

303-
return TargetLoader.Query(InternalEntry);
303+
return TargetLoader.Query(InternalEntityEntry);
304304
}
305305

306306
private void EnsureInitialized()
307-
=> InternalEntry.GetOrCreateCollection(Metadata, forMaterialization: true);
307+
=> InternalEntityEntry.GetOrCreateCollection(Metadata, forMaterialization: true);
308308

309309
/// <summary>
310310
/// The <see cref="EntityEntry" /> of an entity this navigation targets.
@@ -332,7 +332,7 @@ private void EnsureInitialized()
332332
[EntityFrameworkInternal]
333333
protected virtual InternalEntityEntry? GetInternalTargetEntry(object entity)
334334
=> CurrentValue == null
335-
|| !InternalEntry.CollectionContains(Metadata, entity)
335+
|| !InternalEntityEntry.CollectionContains(Metadata, entity)
336336
? null
337337
: InternalEntry.StateManager.GetOrCreateEntry(entity, Metadata.TargetEntityType);
338338

src/EFCore/ChangeTracking/CollectionEntry`.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public CollectionEntry(InternalEntityEntry internalEntry, INavigationBase naviga
5959
/// </remarks>
6060
/// <value> An entry for the entity that owns this member. </value>
6161
public new virtual EntityEntry<TEntity> EntityEntry
62-
=> new(InternalEntry);
62+
=> new(InternalEntityEntry);
6363

6464
/// <summary>
6565
/// Gets or sets the value currently assigned to this property. If the current value is set using this property,
@@ -73,7 +73,7 @@ public CollectionEntry(InternalEntityEntry internalEntry, INavigationBase naviga
7373
/// </remarks>
7474
public new virtual IEnumerable<TRelatedEntity>? CurrentValue
7575
{
76-
get => (IEnumerable<TRelatedEntity>?)this.GetInfrastructure().GetCurrentValue(Metadata);
76+
get => (IEnumerable<TRelatedEntity>?)InternalEntry.GetCurrentValue(Metadata);
7777
set => base.CurrentValue = value;
7878
}
7979

@@ -93,7 +93,7 @@ public CollectionEntry(InternalEntityEntry internalEntry, INavigationBase naviga
9393
/// </remarks>
9494
public new virtual IQueryable<TRelatedEntity> Query()
9595
{
96-
InternalEntry.GetOrCreateCollection(Metadata, forMaterialization: true);
96+
InternalEntityEntry.GetOrCreateCollection(Metadata, forMaterialization: true);
9797

9898
return (IQueryable<TRelatedEntity>)base.Query();
9999
}

src/EFCore/ChangeTracking/ComplexPropertyEntry.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class ComplexPropertyEntry : MemberEntry
2828
/// doing so can result in application failures when updating to a new Entity Framework Core release.
2929
/// </summary>
3030
[EntityFrameworkInternal]
31-
public ComplexPropertyEntry(InternalEntityEntry internalEntry, IComplexProperty complexProperty)
31+
public ComplexPropertyEntry(IInternalEntry internalEntry, IComplexProperty complexProperty)
3232
: base(internalEntry, complexProperty)
3333
{
3434
}
@@ -48,7 +48,7 @@ public ComplexPropertyEntry(InternalEntityEntry internalEntry, IComplexProperty
4848
/// </remarks>
4949
public override bool IsModified
5050
{
51-
get => Metadata.ComplexType.GetFlattenedProperties().Any(property => InternalEntry.IsModified(property));
51+
get => Metadata.ComplexType.GetFlattenedProperties().Any(InternalEntry.IsModified);
5252
set
5353
{
5454
foreach (var property in Metadata.ComplexType.GetFlattenedProperties())

src/EFCore/ChangeTracking/ComplexPropertyEntry`.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class ComplexPropertyEntry<TEntity, TComplexProperty> : ComplexPropertyEn
3131
/// doing so can result in application failures when updating to a new Entity Framework Core release.
3232
/// </summary>
3333
[EntityFrameworkInternal]
34-
public ComplexPropertyEntry(InternalEntityEntry internalEntry, IComplexProperty complexProperty)
34+
public ComplexPropertyEntry(IInternalEntry internalEntry, IComplexProperty complexProperty)
3535
: base(internalEntry, complexProperty)
3636
{
3737
}
@@ -45,7 +45,7 @@ public ComplexPropertyEntry(InternalEntityEntry internalEntry, IComplexProperty
4545
/// examples.
4646
/// </remarks>
4747
public new virtual EntityEntry<TEntity> EntityEntry
48-
=> new(InternalEntry);
48+
=> new(InternalEntry.EntityEntry);
4949

5050
/// <summary>
5151
/// Gets or sets the value currently assigned to this property. If the current value is set using this property,

src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public override void SetValues(PropertyValues propertyValues)
108108
/// doing so can result in application failures when updating to a new Entity Framework Core release.
109109
/// </summary>
110110
public override IReadOnlyList<IProperty> Properties
111-
=> _properties ??= EntityType.GetFlattenedProperties().ToList();
111+
=> _properties ??= [.. EntityType.GetFlattenedProperties()];
112112

113113
/// <summary>
114114
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to

src/EFCore/ChangeTracking/Internal/ChangeDetector.cs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public ChangeDetector(
3838
/// any release. You should only use it directly in your code with extreme caution and knowing that
3939
/// doing so can result in application failures when updating to a new Entity Framework Core release.
4040
/// </summary>
41-
public virtual void PropertyChanged(InternalEntityEntry entry, IPropertyBase propertyBase, bool setModified)
41+
public virtual void PropertyChanged(IInternalEntry entry, IPropertyBase propertyBase, bool setModified)
4242
{
4343
if (entry.EntityState == EntityState.Detached
4444
|| propertyBase is IServiceProperty)
@@ -62,16 +62,16 @@ public virtual void PropertyChanged(InternalEntityEntry entry, IPropertyBase pro
6262
else if (propertyBase.GetRelationshipIndex() != -1
6363
&& propertyBase is INavigationBase navigation)
6464
{
65-
DetectNavigationChange(entry, navigation);
65+
DetectNavigationChange((InternalEntityEntry)entry, navigation);
6666
}
6767
}
6868

69-
private static void ThrowIfKeyChanged(InternalEntityEntry entry, IProperty property)
69+
private static void ThrowIfKeyChanged(IInternalEntry entry, IProperty property)
7070
{
7171
if (property.IsKey()
7272
&& property.GetAfterSaveBehavior() == PropertySaveBehavior.Throw)
7373
{
74-
throw new InvalidOperationException(CoreStrings.KeyReadOnly(property.Name, entry.EntityType.DisplayName()));
74+
throw new InvalidOperationException(CoreStrings.KeyReadOnly(property.Name, entry.StructuralType.DisplayName()));
7575
}
7676
}
7777

@@ -81,15 +81,15 @@ private static void ThrowIfKeyChanged(InternalEntityEntry entry, IProperty prope
8181
/// any release. You should only use it directly in your code with extreme caution and knowing that
8282
/// doing so can result in application failures when updating to a new Entity Framework Core release.
8383
/// </summary>
84-
public virtual void PropertyChanging(InternalEntityEntry entry, IPropertyBase propertyBase)
84+
public virtual void PropertyChanging(IInternalEntry entry, IPropertyBase propertyBase)
8585
{
8686
if (entry.EntityState == EntityState.Detached
8787
|| propertyBase is IServiceProperty)
8888
{
8989
return;
9090
}
9191

92-
if (!entry.EntityType.UseEagerSnapshots())
92+
if (!entry.StructuralType.UseEagerSnapshots())
9393
{
9494
if (propertyBase is IProperty asProperty
9595
&& asProperty.GetOriginalValueIndex() != -1)
@@ -99,7 +99,7 @@ public virtual void PropertyChanging(InternalEntityEntry entry, IPropertyBase pr
9999

100100
if (propertyBase.GetRelationshipIndex() != -1)
101101
{
102-
entry.EnsureRelationshipSnapshot();
102+
((InternalEntityEntry)entry).EnsureRelationshipSnapshot();
103103
}
104104
}
105105
}
@@ -274,7 +274,7 @@ private bool LocalDetectChanges(InternalEntityEntry entry)
274274
/// any release. You should only use it directly in your code with extreme caution and knowing that
275275
/// doing so can result in application failures when updating to a new Entity Framework Core release.
276276
/// </summary>
277-
public bool DetectValueChange(InternalEntityEntry entry, IProperty property)
277+
public bool DetectValueChange(IInternalEntry entry, IProperty property)
278278
{
279279
var current = entry[property];
280280
var original = entry.GetOriginalValue(property);
@@ -296,26 +296,33 @@ public bool DetectValueChange(InternalEntityEntry entry, IProperty property)
296296
return false;
297297
}
298298

299-
private void LogChangeDetected(InternalEntityEntry entry, IProperty property, object? original, object? current)
299+
private void LogChangeDetected(IInternalEntry entry, IProperty property, object? original, object? current)
300300
{
301301
if (_loggingOptions.IsSensitiveDataLoggingEnabled)
302302
{
303-
_logger.PropertyChangeDetectedSensitive(entry, property, original, current);
303+
if (entry is InternalEntityEntry entityEntry)
304+
{
305+
_logger.PropertyChangeDetectedSensitive(entityEntry, property, original, current);
306+
}
304307
}
305308
else
306309
{
307-
_logger.PropertyChangeDetected(entry, property, original, current);
310+
if (entry is InternalEntityEntry entityEntry)
311+
{
312+
_logger.PropertyChangeDetected(entityEntry, property, original, current);
313+
}
308314
}
309315
}
310316

311-
private bool DetectKeyChange(InternalEntityEntry entry, IProperty property)
317+
private bool DetectKeyChange(IInternalEntry entry, IProperty property)
312318
{
313319
if (property.GetRelationshipIndex() < 0)
314320
{
315321
return false;
316322
}
317323

318-
var snapshotValue = entry.GetRelationshipSnapshotValue(property);
324+
var entityEntry = (InternalEntityEntry)entry;
325+
var snapshotValue = entityEntry.GetRelationshipSnapshotValue(property);
319326
var currentValue = entry[property];
320327

321328
var comparer = property.GetKeyValueComparer();
@@ -326,19 +333,19 @@ private bool DetectKeyChange(InternalEntityEntry entry, IProperty property)
326333
{
327334
var keys = property.GetContainingKeys();
328335
var foreignKeys = property.GetContainingForeignKeys()
329-
.Where(fk => fk.DeclaringEntityType.IsAssignableFrom(entry.EntityType));
336+
.Where(fk => fk.DeclaringEntityType.IsAssignableFrom(entityEntry.EntityType));
330337

331338
if (_loggingOptions.IsSensitiveDataLoggingEnabled)
332339
{
333-
_logger.ForeignKeyChangeDetectedSensitive(entry, property, snapshotValue, currentValue);
340+
_logger.ForeignKeyChangeDetectedSensitive(entityEntry, property, snapshotValue, currentValue);
334341
}
335342
else
336343
{
337-
_logger.ForeignKeyChangeDetected(entry, property, snapshotValue, currentValue);
344+
_logger.ForeignKeyChangeDetected(entityEntry, property, snapshotValue, currentValue);
338345
}
339346

340-
entry.StateManager.InternalEntityEntryNotifier.KeyPropertyChanged(
341-
entry, property, keys, foreignKeys, snapshotValue, currentValue);
347+
entityEntry.StateManager.InternalEntityEntryNotifier.KeyPropertyChanged(
348+
entityEntry, property, keys, foreignKeys, snapshotValue, currentValue);
342349

343350
return true;
344351
}
@@ -487,7 +494,6 @@ public virtual void SetEvents(
487494
public virtual void OnDetectingEntityChanges(InternalEntityEntry internalEntityEntry)
488495
{
489496
var @event = DetectingEntityChanges;
490-
491497
if (@event != null)
492498
{
493499
var changeTracker = internalEntityEntry.StateManager.Context.ChangeTracker;

src/EFCore/ChangeTracking/Internal/EmptyShadowValuesFactoryFactory.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ protected override int GetPropertyIndex(IPropertyBase propertyBase)
4040
/// any release. You should only use it directly in your code with extreme caution and knowing that
4141
/// doing so can result in application failures when updating to a new Entity Framework Core release.
4242
/// </summary>
43-
protected override int GetPropertyCount(IRuntimeEntityType entityType)
44-
=> entityType.ShadowPropertyCount;
43+
protected override int GetPropertyCount(IRuntimeTypeBase structuralType)
44+
=> structuralType.ShadowPropertyCount;
4545

4646
/// <summary>
4747
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to

src/EFCore/ChangeTracking/Internal/IChangeDetector.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ public interface IChangeDetector
2323
/// any release. You should only use it directly in your code with extreme caution and knowing that
2424
/// doing so can result in application failures when updating to a new Entity Framework Core release.
2525
/// </summary>
26-
void PropertyChanged(InternalEntityEntry entry, IPropertyBase propertyBase, bool setModified);
26+
void PropertyChanged(IInternalEntry entry, IPropertyBase propertyBase, bool setModified);
2727

2828
/// <summary>
2929
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
3030
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
3131
/// any release. You should only use it directly in your code with extreme caution and knowing that
3232
/// doing so can result in application failures when updating to a new Entity Framework Core release.
3333
/// </summary>
34-
void PropertyChanging(InternalEntityEntry entry, IPropertyBase propertyBase);
34+
void PropertyChanging(IInternalEntry entry, IPropertyBase propertyBase);
3535

3636
/// <summary>
3737
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to

src/EFCore/ChangeTracking/Internal/IInternalEntityEntryNotifier.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,13 @@ void KeyPropertyChanged(
9393
/// any release. You should only use it directly in your code with extreme caution and knowing that
9494
/// doing so can result in application failures when updating to a new Entity Framework Core release.
9595
/// </summary>
96-
void PropertyChanged(InternalEntityEntry entry, IPropertyBase property, bool setModified);
96+
void PropertyChanged(IInternalEntry entry, IPropertyBase property, bool setModified);
9797

9898
/// <summary>
9999
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
100100
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
101101
/// any release. You should only use it directly in your code with extreme caution and knowing that
102102
/// doing so can result in application failures when updating to a new Entity Framework Core release.
103103
/// </summary>
104-
void PropertyChanging(InternalEntityEntry entry, IPropertyBase property);
104+
void PropertyChanging(IInternalEntry entry, IPropertyBase property);
105105
}

0 commit comments

Comments
 (0)