Skip to content

Commit 594688b

Browse files
authored
API review updates (#34241)
Part of #33220 - Replace `IUpdateEntry.GetOriginalOrCurrentValue` with `HasOriginalValue` - Review `MigrationsSqlGenerator.KeyWithOptions` - no longer exists - Rename `TConcreteCollection` to `TConcreteList` for ListOf*Comparer - Consider sealing JsonCollection*ReaderWriter classes - considered, but decided against it. - Obsolete the old CosmosQueryableExtensions.WithPartitionKey overload - Overload resolution picks the obsolete method, so better not to make it obsolete otherwise it is a pain (explicit cast needed) for people attempting to try to use the new method instead of the obsolete one. - Ensure PartitionKey is appropriate for diagnostics - Remove EntityMaterializerSource from QueryContext and QueryContextDependencies
1 parent 92202db commit 594688b

File tree

13 files changed

+47
-61
lines changed

13 files changed

+47
-61
lines changed

src/EFCore.Relational/Update/ColumnModification.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ public virtual object? Value
184184
/// doing so can result in application failures when updating to a new Entity Framework Core release.
185185
/// </summary>
186186
public static object? GetOriginalValue(IUpdateEntry entry, IProperty property)
187-
=> entry.GetOriginalOrCurrentValue(property);
187+
=> entry.CanHaveOriginalValue(property) ? entry.GetOriginalValue(property) : entry.GetCurrentValue(property);
188188

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

src/EFCore/ChangeTracking/Internal/CompositePrincipalKeyValueFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public virtual IProperty FindNullPropertyInKeyValues(IReadOnlyList<object?> keyV
9999
/// doing so can result in application failures when updating to a new Entity Framework Core release.
100100
/// </summary>
101101
public virtual IReadOnlyList<object?> CreateFromOriginalValues(IUpdateEntry entry)
102-
=> CreateFromEntry(entry, (e, p) => e.GetOriginalOrCurrentValue(p));
102+
=> CreateFromEntry(entry, (e, p) => e.CanHaveOriginalValue(p) ? e.GetOriginalValue(p) : e.GetCurrentValue(p));
103103

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

src/EFCore/ChangeTracking/Internal/CompositeValueFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public virtual bool TryCreateFromPreStoreGeneratedCurrentValues(IUpdateEntry ent
9191
/// doing so can result in application failures when updating to a new Entity Framework Core release.
9292
/// </summary>
9393
public virtual bool TryCreateFromOriginalValues(IUpdateEntry entry, [NotNullWhen(true)] out IReadOnlyList<object?>? key)
94-
=> TryCreateFromEntry(entry, (e, p) => e.GetOriginalOrCurrentValue(p), out key);
94+
=> TryCreateFromEntry(entry, (e, p) => e.CanHaveOriginalValue(p) ? e.GetOriginalValue(p) : e.GetCurrentValue(p), out key);
9595

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

src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,10 +1141,8 @@ public bool RemoveFromCollection(INavigationBase navigationBase, object value)
11411141
/// any release. You should only use it directly in your code with extreme caution and knowing that
11421142
/// doing so can result in application failures when updating to a new Entity Framework Core release.
11431143
/// </summary>
1144-
public object? GetOriginalOrCurrentValue(IPropertyBase propertyBase)
1145-
=> propertyBase.GetOriginalValueIndex() >= 0
1146-
? _originalValues.GetValue(this, (IProperty)propertyBase)
1147-
: GetCurrentValue(propertyBase);
1144+
public bool CanHaveOriginalValue(IPropertyBase propertyBase)
1145+
=> propertyBase.GetOriginalValueIndex() >= 0;
11481146

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

src/EFCore/ChangeTracking/ListOfNullableValueTypesComparer.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,31 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking;
1111
/// </summary>
1212
/// <remarks>
1313
/// <para>
14-
/// This comparer should be used for nullable value types. Use <see cref="ListOfNullableValueTypesComparer{TConcreteCollection,TElement}" /> for reference
14+
/// This comparer should be used for nullable value types. Use <see cref="ListOfNullableValueTypesComparer{TConcreteList,TElement}" /> for reference
1515
/// types and non-nullable value types.
1616
/// </para>
1717
/// <para>
1818
/// See <see href="https://aka.ms/efcore-docs-value-comparers">EF Core value comparers</see> for more information and examples.
1919
/// </para>
2020
/// </remarks>
21-
/// <typeparam name="TConcreteCollection">The collection type to create an index of, if needed.</typeparam>
21+
/// <typeparam name="TConcreteList">The collection type to create an index of, if needed.</typeparam>
2222
/// <typeparam name="TElement">The element type.</typeparam>
23-
public sealed class ListOfNullableValueTypesComparer<TConcreteCollection, TElement> : ValueComparer<IEnumerable<TElement?>>, IInfrastructure<ValueComparer>
23+
public sealed class ListOfNullableValueTypesComparer<TConcreteList, TElement> : ValueComparer<IEnumerable<TElement?>>, IInfrastructure<ValueComparer>
2424
where TElement : struct
2525
{
26-
private static readonly bool IsArray = typeof(TConcreteCollection).IsArray;
26+
private static readonly bool IsArray = typeof(TConcreteList).IsArray;
2727

2828
private static readonly bool IsReadOnly = IsArray
29-
|| (typeof(TConcreteCollection).IsGenericType
30-
&& typeof(TConcreteCollection).GetGenericTypeDefinition() == typeof(ReadOnlyCollection<>));
29+
|| (typeof(TConcreteList).IsGenericType
30+
&& typeof(TConcreteList).GetGenericTypeDefinition() == typeof(ReadOnlyCollection<>));
3131

32-
private static readonly MethodInfo CompareMethod = typeof(ListOfNullableValueTypesComparer<TConcreteCollection, TElement>).GetMethod(
32+
private static readonly MethodInfo CompareMethod = typeof(ListOfNullableValueTypesComparer<TConcreteList, TElement>).GetMethod(
3333
nameof(Compare), BindingFlags.Static | BindingFlags.NonPublic, [typeof(IEnumerable<TElement?>), typeof(IEnumerable<TElement?>), typeof(ValueComparer<TElement?>)])!;
3434

35-
private static readonly MethodInfo GetHashCodeMethod = typeof(ListOfNullableValueTypesComparer<TConcreteCollection, TElement>).GetMethod(
35+
private static readonly MethodInfo GetHashCodeMethod = typeof(ListOfNullableValueTypesComparer<TConcreteList, TElement>).GetMethod(
3636
nameof(GetHashCode), BindingFlags.Static | BindingFlags.NonPublic, [typeof(IEnumerable<TElement?>), typeof(ValueComparer<TElement?>)])!;
3737

38-
private static readonly MethodInfo SnapshotMethod = typeof(ListOfNullableValueTypesComparer<TConcreteCollection, TElement>).GetMethod(
38+
private static readonly MethodInfo SnapshotMethod = typeof(ListOfNullableValueTypesComparer<TConcreteList, TElement>).GetMethod(
3939
nameof(Snapshot), BindingFlags.Static | BindingFlags.NonPublic, [typeof(IEnumerable<TElement?>), typeof(ValueComparer<TElement?>)])!;
4040

4141
/// <summary>
@@ -198,14 +198,14 @@ private static int GetHashCode(IEnumerable<TElement?> source, ValueComparer<TEle
198198
}
199199
else
200200
{
201-
var snapshot = IsReadOnly ? new List<TElement?>() : (IList<TElement?>)Activator.CreateInstance<TConcreteCollection>()!;
201+
var snapshot = IsReadOnly ? new List<TElement?>() : (IList<TElement?>)Activator.CreateInstance<TConcreteList>()!;
202202
foreach (var e in sourceList)
203203
{
204204
snapshot.Add(e == null ? null : elementComparer.Snapshot(e));
205205
}
206206

207207
return IsReadOnly
208-
? (IList<TElement?>)Activator.CreateInstance(typeof(TConcreteCollection), [snapshot])!
208+
? (IList<TElement?>)Activator.CreateInstance(typeof(TConcreteList), [snapshot])!
209209
: snapshot;
210210
}
211211
}

src/EFCore/ChangeTracking/ListOfReferenceTypesComparer.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,24 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking;
1818
/// See <see href="https://aka.ms/efcore-docs-value-comparers">EF Core value comparers</see> for more information and examples.
1919
/// </para>
2020
/// </remarks>
21-
/// <typeparam name="TConcreteCollection">The collection type to create an index of, if needed.</typeparam>
21+
/// <typeparam name="TConcreteList">The collection type to create an index of, if needed.</typeparam>
2222
/// <typeparam name="TElement">The element type.</typeparam>
23-
public sealed class ListOfReferenceTypesComparer<TConcreteCollection, TElement> : ValueComparer<object>, IInfrastructure<ValueComparer>
23+
public sealed class ListOfReferenceTypesComparer<TConcreteList, TElement> : ValueComparer<object>, IInfrastructure<ValueComparer>
2424
where TElement : class
2525
{
26-
private static readonly bool IsArray = typeof(TConcreteCollection).IsArray;
26+
private static readonly bool IsArray = typeof(TConcreteList).IsArray;
2727

2828
private static readonly bool IsReadOnly = IsArray
29-
|| (typeof(TConcreteCollection).IsGenericType
30-
&& typeof(TConcreteCollection).GetGenericTypeDefinition() == typeof(ReadOnlyCollection<>));
29+
|| (typeof(TConcreteList).IsGenericType
30+
&& typeof(TConcreteList).GetGenericTypeDefinition() == typeof(ReadOnlyCollection<>));
3131

32-
private static readonly MethodInfo CompareMethod = typeof(ListOfReferenceTypesComparer<TConcreteCollection, TElement>).GetMethod(
32+
private static readonly MethodInfo CompareMethod = typeof(ListOfReferenceTypesComparer<TConcreteList, TElement>).GetMethod(
3333
nameof(Compare), BindingFlags.Static | BindingFlags.NonPublic, [typeof(object), typeof(object), typeof(ValueComparer)])!;
3434

35-
private static readonly MethodInfo GetHashCodeMethod = typeof(ListOfReferenceTypesComparer<TConcreteCollection, TElement>).GetMethod(
35+
private static readonly MethodInfo GetHashCodeMethod = typeof(ListOfReferenceTypesComparer<TConcreteList, TElement>).GetMethod(
3636
nameof(GetHashCode), BindingFlags.Static | BindingFlags.NonPublic, [typeof(IEnumerable), typeof(ValueComparer)])!;
3737

38-
private static readonly MethodInfo SnapshotMethod = typeof(ListOfReferenceTypesComparer<TConcreteCollection, TElement>).GetMethod(
38+
private static readonly MethodInfo SnapshotMethod = typeof(ListOfReferenceTypesComparer<TConcreteList, TElement>).GetMethod(
3939
nameof(Snapshot), BindingFlags.Static | BindingFlags.NonPublic, [typeof(object), typeof(ValueComparer)])!;
4040

4141
/// <summary>
@@ -194,14 +194,14 @@ private static int GetHashCode(IEnumerable source, ValueComparer elementComparer
194194
}
195195
else
196196
{
197-
var snapshot = IsReadOnly ? new List<TElement?>() : (IList<TElement?>)Activator.CreateInstance<TConcreteCollection>()!;
197+
var snapshot = IsReadOnly ? new List<TElement?>() : (IList<TElement?>)Activator.CreateInstance<TConcreteList>()!;
198198
foreach (var e in sourceList)
199199
{
200200
snapshot.Add(e == null ? null : (TElement?)elementComparer.Snapshot(e));
201201
}
202202

203203
return IsReadOnly
204-
? (IList<TElement?>)Activator.CreateInstance(typeof(TConcreteCollection), [snapshot])!
204+
? (IList<TElement?>)Activator.CreateInstance(typeof(TConcreteList), [snapshot])!
205205
: snapshot;
206206
}
207207
}

src/EFCore/ChangeTracking/ListOfValueTypesComparer.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,30 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking;
1212
/// <remarks>
1313
/// <para>
1414
/// This comparer should be used for reference types and non-nullable value types. Use
15-
/// <see cref="ListOfNullableValueTypesComparer{TConcreteCollection,TElement}" /> for nullable value types.
15+
/// <see cref="ListOfNullableValueTypesComparer{TConcreteList,TElement}" /> for nullable value types.
1616
/// </para>
1717
/// <para>
1818
/// See <see href="https://aka.ms/efcore-docs-value-comparers">EF Core value comparers</see> for more information and examples.
1919
/// </para>
2020
/// </remarks>
21-
/// <typeparam name="TConcreteCollection">The collection type to create an index of, if needed.</typeparam>
21+
/// <typeparam name="TConcreteList">The collection type to create an index of, if needed.</typeparam>
2222
/// <typeparam name="TElement">The element type.</typeparam>
23-
public sealed class ListOfValueTypesComparer<TConcreteCollection, TElement> : ValueComparer<IEnumerable<TElement>>, IInfrastructure<ValueComparer>
23+
public sealed class ListOfValueTypesComparer<TConcreteList, TElement> : ValueComparer<IEnumerable<TElement>>, IInfrastructure<ValueComparer>
2424
where TElement : struct
2525
{
26-
private static readonly bool IsArray = typeof(TConcreteCollection).IsArray;
26+
private static readonly bool IsArray = typeof(TConcreteList).IsArray;
2727

2828
private static readonly bool IsReadOnly = IsArray
29-
|| (typeof(TConcreteCollection).IsGenericType
30-
&& typeof(TConcreteCollection).GetGenericTypeDefinition() == typeof(ReadOnlyCollection<>));
29+
|| (typeof(TConcreteList).IsGenericType
30+
&& typeof(TConcreteList).GetGenericTypeDefinition() == typeof(ReadOnlyCollection<>));
3131

32-
private static readonly MethodInfo CompareMethod = typeof(ListOfValueTypesComparer<TConcreteCollection, TElement>).GetMethod(
32+
private static readonly MethodInfo CompareMethod = typeof(ListOfValueTypesComparer<TConcreteList, TElement>).GetMethod(
3333
nameof(Compare), BindingFlags.Static | BindingFlags.NonPublic, [typeof(IEnumerable<TElement>), typeof(IEnumerable<TElement>), typeof(ValueComparer<TElement>)])!;
3434

35-
private static readonly MethodInfo GetHashCodeMethod = typeof(ListOfValueTypesComparer<TConcreteCollection, TElement>).GetMethod(
35+
private static readonly MethodInfo GetHashCodeMethod = typeof(ListOfValueTypesComparer<TConcreteList, TElement>).GetMethod(
3636
nameof(GetHashCode), BindingFlags.Static | BindingFlags.NonPublic, [typeof(IEnumerable<TElement>), typeof(ValueComparer<TElement>)])!;
3737

38-
private static readonly MethodInfo SnapshotMethod = typeof(ListOfValueTypesComparer<TConcreteCollection, TElement>).GetMethod(
38+
private static readonly MethodInfo SnapshotMethod = typeof(ListOfValueTypesComparer<TConcreteList, TElement>).GetMethod(
3939
nameof(Snapshot), BindingFlags.Static | BindingFlags.NonPublic, [typeof(IEnumerable<TElement>), typeof(ValueComparer<TElement>)])!;
4040

4141
/// <summary>
@@ -183,14 +183,14 @@ private static IList<TElement> Snapshot(IEnumerable<TElement> source, ValueCompa
183183
}
184184
else
185185
{
186-
var snapshot = IsReadOnly ? new List<TElement>() : (IList<TElement>)Activator.CreateInstance<TConcreteCollection>()!;
186+
var snapshot = IsReadOnly ? new List<TElement>() : (IList<TElement>)Activator.CreateInstance<TConcreteList>()!;
187187
foreach (var e in sourceList)
188188
{
189189
snapshot.Add(elementComparer.Snapshot(e));
190190
}
191191

192192
return IsReadOnly
193-
? (IList<TElement>)Activator.CreateInstance(typeof(TConcreteCollection), [snapshot])!
193+
? (IList<TElement>)Activator.CreateInstance(typeof(TConcreteList), [snapshot])!
194194
: snapshot;
195195
}
196196
}

src/EFCore/Query/QueryContext.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
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.Diagnostics.CodeAnalysis;
54
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
65
using Microsoft.EntityFrameworkCore.Query.Internal;
76

@@ -51,12 +50,6 @@ protected QueryContext(QueryContextDependencies dependencies)
5150
/// </summary>
5251
protected virtual QueryContextDependencies Dependencies { get; }
5352

54-
/// <summary>
55-
/// The <see cref="EntityMaterializerSource"/>, which can be used to create stand-alone entity instances.
56-
/// </summary>
57-
public virtual IEntityMaterializerSource EntityMaterializerSource
58-
=> Dependencies.EntityMaterializerSource;
59-
6053
/// <summary>
6154
/// Sets the navigation for given entity as loaded.
6255
/// </summary>

src/EFCore/Query/QueryContextDependencies.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,13 @@ public QueryContextDependencies(
5353
IExecutionStrategy executionStrategy,
5454
IConcurrencyDetector concurrencyDetector,
5555
IExceptionDetector exceptionDetector,
56-
IEntityMaterializerSource entityMaterializerSource,
5756
IDiagnosticsLogger<DbLoggerCategory.Database.Command> commandLogger,
5857
IDiagnosticsLogger<DbLoggerCategory.Query> queryLogger)
5958
{
6059
CurrentContext = currentContext;
6160
ExecutionStrategy = executionStrategy;
6261
ConcurrencyDetector = concurrencyDetector;
6362
ExceptionDetector = exceptionDetector;
64-
EntityMaterializerSource = entityMaterializerSource;
6563
CommandLogger = commandLogger;
6664
QueryLogger = queryLogger;
6765
}
@@ -96,11 +94,6 @@ public IStateManager StateManager
9694
/// </summary>
9795
public IExceptionDetector ExceptionDetector { get; init; }
9896

99-
/// <summary>
100-
/// The <see cref="EntityMaterializerSource"/>, which can be used to create stand-alone entity instances.
101-
/// </summary>
102-
public IEntityMaterializerSource EntityMaterializerSource { get; }
103-
10497
/// <summary>
10598
/// The command logger.
10699
/// </summary>

src/EFCore/Update/IUpdateEntry.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,11 @@ public interface IUpdateEntry
9595
object? GetOriginalValue(IPropertyBase propertyBase);
9696

9797
/// <summary>
98-
/// Gets the value assigned to the property when it was retrieved from the database, or
99-
/// the current value if the original value is not being stored.
98+
/// Returns <see langword="true"/> only if the property has storage for an original value.
10099
/// </summary>
101-
/// <param name="propertyBase">The property to get the value for.</param>
102-
/// <returns>The value for the property.</returns>
103-
object? GetOriginalOrCurrentValue(IPropertyBase propertyBase);
100+
/// <param name="propertyBase">The property.</param>
101+
/// <returns><see langword="true"/> if the property may have an original value; <see langword="false"/> if it never can.</returns>
102+
bool CanHaveOriginalValue(IPropertyBase propertyBase);
104103

105104
/// <summary>
106105
/// Gets the value assigned to the property.

src/EFCore/Update/UpdateEntryExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ public static class UpdateEntryExtensions
4949
/// <returns>The value for the property.</returns>
5050
public static object? GetOriginalProviderValue(this IUpdateEntry updateEntry, IProperty property)
5151
{
52-
var value = updateEntry.GetOriginalOrCurrentValue(property);
52+
var value = updateEntry.CanHaveOriginalValue(property)
53+
? updateEntry.GetOriginalValue(property)
54+
: updateEntry.GetCurrentValue(property);
55+
5356
var typeMapping = property.GetTypeMapping();
5457
value = value?.GetType().IsInteger() == true && typeMapping.ClrType.UnwrapNullableType().IsEnum
5558
? Enum.ToObject(typeMapping.ClrType.UnwrapNullableType(), value)

test/EFCore.Cosmos.FunctionalTests/TestUtilities/CosmosTestStore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ public IUpdateEntry SharedIdentityEntry
531531
public object GetCurrentValue(IPropertyBase propertyBase)
532532
=> throw new NotImplementedException();
533533

534-
public object GetOriginalOrCurrentValue(IPropertyBase propertyBase)
534+
public bool CanHaveOriginalValue(IPropertyBase propertyBase)
535535
=> throw new NotImplementedException();
536536

537537
public TProperty GetCurrentValue<TProperty>(IPropertyBase propertyBase)

test/EFCore.Tests/ExceptionTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ public object GetCurrentValue(IPropertyBase propertyBase)
130130
public object GetOriginalValue(IPropertyBase propertyBase)
131131
=> throw new NotImplementedException();
132132

133-
public object GetOriginalOrCurrentValue(IPropertyBase propertyBase)
133+
public bool CanHaveOriginalValue(IPropertyBase propertyBase)
134134
=> throw new NotImplementedException();
135135

136136
public TProperty GetCurrentValue<TProperty>(IPropertyBase propertyBase)

0 commit comments

Comments
 (0)