Skip to content

Commit 7a00395

Browse files
authored
Refactor complex property change tracking (#35857)
Part of #31237
1 parent 667c647 commit 7a00395

File tree

124 files changed

+9070
-11261
lines changed

Some content is hidden

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

124 files changed

+9070
-11261
lines changed

src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs

+13-27
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace Microsoft.EntityFrameworkCore.Query.Internal;
2222
/// any release. You should only use it directly in your code with extreme caution and knowing that
2323
/// doing so can result in application failures when updating to a new Entity Framework Core release.
2424
/// </summary>
25-
public class LinqToCSharpSyntaxTranslator : ExpressionVisitor
25+
public class LinqToCSharpSyntaxTranslator(SyntaxGenerator syntaxGenerator) : ExpressionVisitor
2626
{
2727
private sealed record StackFrame(
2828
Dictionary<ParameterExpression, string> Variables,
@@ -38,7 +38,7 @@ private readonly Stack<StackFrame> _stack
3838
private sealed record LiftedState
3939
{
4040
internal readonly List<StatementSyntax> Statements = [];
41-
internal readonly Dictionary<ParameterExpression, string> Variables = new();
41+
internal readonly Dictionary<ParameterExpression, string> Variables = [];
4242
internal readonly HashSet<string> VariableNames = [];
4343
internal readonly List<LocalDeclarationStatementSyntax> UnassignedVariableDeclarations = [];
4444

@@ -65,25 +65,16 @@ internal LiftedState CreateChild()
6565

6666
private readonly HashSet<ParameterExpression> _capturedVariables = [];
6767
private ISet<string> _collectedNamespaces = null!;
68-
private readonly Dictionary<MethodBase, MethodDeclarationSyntax> _methodUnsafeAccessors = new();
69-
private readonly Dictionary<(FieldInfo Field, bool ForWrite), MethodDeclarationSyntax> _fieldUnsafeAccessors = new();
68+
private readonly Dictionary<MethodBase, MethodDeclarationSyntax> _methodUnsafeAccessors = [];
69+
private readonly Dictionary<(FieldInfo Field, bool ForWrite), MethodDeclarationSyntax> _fieldUnsafeAccessors = [];
7070

7171
private static MethodInfo? _mathPowMethod;
7272

7373
private readonly SideEffectDetectionSyntaxWalker _sideEffectDetector = new();
7474
private readonly ConstantDetectionSyntaxWalker _constantDetector = new();
75-
private readonly SyntaxGenerator _g;
75+
private readonly SyntaxGenerator _g = syntaxGenerator;
7676
private readonly StringBuilder _stringBuilder = new();
7777

78-
/// <summary>
79-
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
80-
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
81-
/// any release. You should only use it directly in your code with extreme caution and knowing that
82-
/// doing so can result in application failures when updating to a new Entity Framework Core release.
83-
/// </summary>
84-
public LinqToCSharpSyntaxTranslator(SyntaxGenerator syntaxGenerator)
85-
=> _g = syntaxGenerator;
86-
8778
/// <summary>
8879
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
8980
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -422,14 +413,9 @@ Expression VisitAssignment(BinaryExpression assignment, SyntaxKind kind)
422413

423414
// If the RHS was lifted out and the assignment lowering succeeded, Translate above returns the lowered assignment variable;
424415
// this would mean that we return a useless identity assignment (i = i). Instead, just return it.
425-
if (translatedRight == translatedLeft)
426-
{
427-
Result = translatedRight;
428-
}
429-
else
430-
{
431-
Result = AssignmentExpression(kind, translatedLeft, translatedRight);
432-
}
416+
Result = translatedRight == translatedLeft
417+
? translatedRight
418+
: (SyntaxNode)AssignmentExpression(kind, translatedLeft, translatedRight);
433419

434420
return assignment;
435421
}
@@ -1474,7 +1460,7 @@ NameSyntax GenerateGenericType(Type type, List<TypeSyntax> genericArguments, int
14741460
SimpleNameSyntax nameSyntax = genericPartIndex <= 0
14751461
? IdentifierName(type.Name)
14761462
: GenericName(
1477-
Identifier(type.Name.Substring(0, genericPartIndex)),
1463+
Identifier(type.Name[..genericPartIndex]),
14781464
TypeArgumentList(SeparatedList(genericArguments.Skip(offset).Take(length - offset))));
14791465
if (type.DeclaringType == null)
14801466
{
@@ -1637,7 +1623,7 @@ when constantExpression.Type.Attributes.HasFlag(TypeAttributes.NestedPrivate)
16371623
{ Expression: null } => Generate(member.Member.DeclaringType!),
16381624

16391625
// If the member is declared on an interface, add a cast up to it, to handle explicit interface implementation.
1640-
_ when member.Member.DeclaringType is { IsInterface: true }
1626+
_ when member.Member.DeclaringType is { IsInterface: true } && member.Expression.Type != member.Member.DeclaringType
16411627
=> ParenthesizedExpression(
16421628
CastExpression(Generate(member.Member.DeclaringType), Translate<ExpressionSyntax>(member.Expression))),
16431629

@@ -2212,7 +2198,7 @@ SyntaxList<StatementSyntax> ProcessArmBody(Expression body)
22122198
var result = translatedBody switch
22132199
{
22142200
BlockSyntax block => SingletonList<StatementSyntax>(block.WithStatements(block.Statements.Add(BreakStatement()))),
2215-
StatementSyntax s => List(new[] { s, BreakStatement() }),
2201+
StatementSyntax s => List([s, BreakStatement()]),
22162202
ExpressionSyntax e => List(new StatementSyntax[] { ExpressionStatement(e), BreakStatement() }),
22172203

22182204
_ => throw new ArgumentOutOfRangeException()
@@ -2379,14 +2365,14 @@ protected override Expression VisitTry(TryExpression tryNode)
23792365
var translatedBody = Translate(tryNode.Body) switch
23802366
{
23812367
BlockSyntax b => (IEnumerable<SyntaxNode>)b.Statements,
2382-
var n => new[] { n }
2368+
var n => [n]
23832369
};
23842370

23852371
var translatedFinally = Translate(tryNode.Finally) switch
23862372
{
23872373
BlockSyntax b => (IEnumerable<SyntaxNode>)b.Statements,
23882374
null => null,
2389-
var n => new[] { n }
2375+
var n => [n]
23902376
};
23912377

23922378
switch (_context)

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

+1-10
Original file line numberDiff line numberDiff line change
@@ -1566,8 +1566,7 @@ private void
15661566
out var currentValueGetter,
15671567
out var preStoreGeneratedCurrentValueGetter,
15681568
out var originalValueGetter,
1569-
out var relationshipSnapshotGetter,
1570-
out var valueBufferGetter);
1569+
out var relationshipSnapshotGetter);
15711570

15721571
mainBuilder
15731572
.Append(variableName).AppendLine(".SetAccessors(")
@@ -1594,14 +1593,6 @@ private void
15941593
_code.Expression(
15951594
relationshipSnapshotGetter, parameters.Namespaces, unsafeAccessors,
15961595
(IReadOnlyDictionary<object, string>)parameters.ScopeVariables, memberAccessReplacements), skipFinalNewline: true)
1597-
.AppendLine(",")
1598-
.AppendLines(
1599-
valueBufferGetter == null
1600-
? "null"
1601-
: _code.Expression(
1602-
valueBufferGetter, parameters.Namespaces, unsafeAccessors,
1603-
(IReadOnlyDictionary<object, string>)parameters.ScopeVariables, memberAccessReplacements),
1604-
skipFinalNewline: true)
16051596
.AppendLine(");")
16061597
.DecrementIndent();
16071598

src/EFCore/ChangeTracking/IDependentKeyValueFactory`.cs

-10
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,6 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking;
2222
/// <typeparam name="TKey">The generic type of the key.</typeparam>
2323
public interface IDependentKeyValueFactory<TKey> : IDependentKeyValueFactory
2424
{
25-
/// <summary>
26-
/// Attempts to create a key instance using foreign key values from the given <see cref="ValueBuffer" />.
27-
/// </summary>
28-
/// <param name="valueBuffer">The value buffer representing the entity instance.</param>
29-
/// <param name="key">The key instance.</param>
30-
/// <returns><see langword="true" /> if the key instance was created; <see langword="false" /> otherwise.</returns>
31-
[ContractAnnotation("=>true, key:notnull; =>false, key:null")]
32-
[Obsolete]
33-
bool TryCreateFromBuffer(in ValueBuffer valueBuffer, [NotNullWhen(true)] out TKey? key);
34-
3525
/// <summary>
3626
/// Attempts to create a key instance using foreign key values from the given <see cref="IUpdateEntry" />.
3727
/// </summary>

src/EFCore/ChangeTracking/IPrincipalKeyValueFactory`.cs

-8
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,6 @@ public interface IPrincipalKeyValueFactory<TKey> : IPrincipalKeyValueFactory
2626
/// <returns>The key object, or null if any of the key values were null.</returns>
2727
object? CreateFromKeyValues(IReadOnlyList<object?> keyValues);
2828

29-
/// <summary>
30-
/// Creates a key object from key values obtained from their indexed position in the given <see cref="ValueBuffer" />.
31-
/// </summary>
32-
/// <param name="valueBuffer">The buffer containing key values.</param>
33-
/// <returns>The key object, or null if any of the key values were null.</returns>
34-
[Obsolete]
35-
object? CreateFromBuffer(ValueBuffer valueBuffer);
36-
3729
/// <summary>
3830
/// Finds the first null in the given in-order array of key values and returns the associated <see cref="IProperty" />.
3931
/// </summary>

0 commit comments

Comments
 (0)