Skip to content

Commit c50e2f6

Browse files
authored
Add NativeAOT support for Change Tracking
Part of #29761
1 parent b931a3d commit c50e2f6

22 files changed

+1013
-179
lines changed

All.sln

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
99
azure-pipelines.yml = azure-pipelines.yml
1010
Directory.Build.props = Directory.Build.props
1111
Directory.Build.targets = Directory.Build.targets
12+
global.json = global.json
1213
tools\Resources.tt = tools\Resources.tt
1314
eng\Versions.props = eng\Versions.props
1415
EndProjectSection
@@ -125,6 +126,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFCore.Trimming.Tests", "te
125126
EndProject
126127
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFCore.Templates", "src\EFCore.Templates\EFCore.Templates.csproj", "{1FE385D8-8F8B-4EC9-A1A9-AFCC38B8546C}"
127128
EndProject
129+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFCore.NativeAotTests", "test\EFCore.NativeAotTests\EFCore.NativeAotTests.csproj", "{2487950B-403A-482C-8ED3-CCF31E9E677F}"
130+
EndProject
128131
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFCore.SqlServer.HierarchyId", "src\EFCore.SqlServer.HierarchyId\EFCore.SqlServer.HierarchyId.csproj", "{8F722A02-71A4-4787-ACD8-FB7D5B7AE648}"
129132
EndProject
130133
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFCore.SqlServer.HierarchyId.Tests", "test\EFCore.SqlServer.HierarchyId.Tests\EFCore.SqlServer.HierarchyId.Tests.csproj", "{01F86E65-6448-424C-AAB5-9C6427EF6FD4}"
@@ -339,6 +342,10 @@ Global
339342
{1FE385D8-8F8B-4EC9-A1A9-AFCC38B8546C}.Debug|Any CPU.Build.0 = Debug|Any CPU
340343
{1FE385D8-8F8B-4EC9-A1A9-AFCC38B8546C}.Release|Any CPU.ActiveCfg = Release|Any CPU
341344
{1FE385D8-8F8B-4EC9-A1A9-AFCC38B8546C}.Release|Any CPU.Build.0 = Release|Any CPU
345+
{2487950B-403A-482C-8ED3-CCF31E9E677F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
346+
{2487950B-403A-482C-8ED3-CCF31E9E677F}.Debug|Any CPU.Build.0 = Debug|Any CPU
347+
{2487950B-403A-482C-8ED3-CCF31E9E677F}.Release|Any CPU.ActiveCfg = Release|Any CPU
348+
{2487950B-403A-482C-8ED3-CCF31E9E677F}.Release|Any CPU.Build.0 = Release|Any CPU
342349
{8F722A02-71A4-4787-ACD8-FB7D5B7AE648}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
343350
{8F722A02-71A4-4787-ACD8-FB7D5B7AE648}.Debug|Any CPU.Build.0 = Debug|Any CPU
344351
{8F722A02-71A4-4787-ACD8-FB7D5B7AE648}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -410,6 +417,7 @@ Global
410417
{F1B2E5A0-8C74-414A-B262-353FEE325E9F} = {258D5057-81B9-40EC-A872-D21E27452749}
411418
{933C8662-817C-4F45-B98B-6557E28F7BB1} = {258D5057-81B9-40EC-A872-D21E27452749}
412419
{1FE385D8-8F8B-4EC9-A1A9-AFCC38B8546C} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}
420+
{2487950B-403A-482C-8ED3-CCF31E9E677F} = {258D5057-81B9-40EC-A872-D21E27452749}
413421
{8F722A02-71A4-4787-ACD8-FB7D5B7AE648} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}
414422
{01F86E65-6448-424C-AAB5-9C6427EF6FD4} = {258D5057-81B9-40EC-A872-D21E27452749}
415423
{3D935B7D-80BD-49AD-BDC9-E1B0C9D9494F} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}

eng/common/tools.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -760,9 +760,9 @@ function MSBuild() {
760760
(Join-Path $basePath (Join-Path $buildTool.Framework 'Microsoft.DotNet.ArcadeLogging.dll')),
761761
(Join-Path $basePath (Join-Path $buildTool.Framework 'Microsoft.DotNet.Arcade.Sdk.dll')),
762762
(Join-Path $basePath (Join-Path netcoreapp2.1 'Microsoft.DotNet.ArcadeLogging.dll')),
763-
(Join-Path $basePath (Join-Path netcoreapp2.1 'Microsoft.DotNet.Arcade.Sdk.dll'))
763+
(Join-Path $basePath (Join-Path netcoreapp2.1 'Microsoft.DotNet.Arcade.Sdk.dll')),
764764
(Join-Path $basePath (Join-Path netcoreapp3.1 'Microsoft.DotNet.ArcadeLogging.dll')),
765-
(Join-Path $basePath (Join-Path netcoreapp3.1 'Microsoft.DotNet.Arcade.Sdk.dll'))
765+
(Join-Path $basePath (Join-Path netcoreapp3.1 'Microsoft.DotNet.Arcade.Sdk.dll')),
766766
(Join-Path $basePath (Join-Path net7.0 'Microsoft.DotNet.ArcadeLogging.dll')),
767767
(Join-Path $basePath (Join-Path net7.0 'Microsoft.DotNet.Arcade.Sdk.dll'))
768768
)

eng/helix.proj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@
2929
<XUnitProject Remove="$(RepoRoot)/test/EFCore.Specification.Tests/*.csproj"/>
3030
<XUnitProject Remove="$(RepoRoot)/test/EFCore.AspNet.Specification.Tests/*.csproj"/>
3131
<XUnitProject Remove="$(RepoRoot)/test/EFCore.Relational.Specification.Tests/*.csproj"/>
32-
<!-- The trimming test project is a console program -->
32+
<!-- The trimming and NativeAOT test projects are console programs -->
3333
<XUnitProject Remove="$(RepoRoot)/test/EFCore.Trimming.Tests/*.csproj"/>
34+
<XUnitProject Remove="$(RepoRoot)/test/EFCore.NativeAotTests/*.csproj"/>
3435
</ItemGroup>
3536

3637
<!-- Work-around for https://github.com/dotnet/runtime/issues/70758 -->

src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.ComponentModel;
66
using System.Diagnostics.CodeAnalysis;
77
using System.Runtime.CompilerServices;
8-
using JetBrains.Annotations;
98
using Microsoft.EntityFrameworkCore.Internal;
109
using Microsoft.EntityFrameworkCore.Metadata.Internal;
1110

@@ -185,26 +184,22 @@ public async Task SetEntityStateAsync(
185184
CancellationToken cancellationToken = default)
186185
{
187186
var oldState = _stateData.EntityState;
188-
var adding = false;
189-
await SetupAsync().ConfigureAwait(false);
187+
bool adding = PrepareForAdd(entityState);
188+
entityState = await PropagateToUnknownKeyAsync(
189+
oldState, entityState, adding, forceStateWhenUnknownKey, cancellationToken).ConfigureAwait(false);
190190

191191
if ((adding || oldState is EntityState.Detached)
192192
&& await StateManager.ValueGenerationManager
193193
.GenerateAsync(this, includePrimaryKey: adding, cancellationToken).ConfigureAwait(false)
194194
&& fallbackState.HasValue)
195195
{
196196
entityState = fallbackState.Value;
197-
await SetupAsync().ConfigureAwait(false);
198-
}
199-
200-
SetEntityState(oldState, entityState, acceptChanges, modifyProperties);
201-
202-
async Task SetupAsync()
203-
{
204197
adding = PrepareForAdd(entityState);
205198
entityState = await PropagateToUnknownKeyAsync(
206199
oldState, entityState, adding, forceStateWhenUnknownKey, cancellationToken).ConfigureAwait(false);
207200
}
201+
202+
SetEntityState(oldState, entityState, acceptChanges, modifyProperties);
208203
}
209204

210205
private EntityState PropagateToUnknownKey(
@@ -829,8 +824,13 @@ private static readonly MethodInfo ReadOriginalValueMethod
829824
internal static MethodInfo MakeReadOriginalValueMethod(Type type)
830825
=> ReadOriginalValueMethod.MakeGenericMethod(type);
831826

832-
[UsedImplicitly]
833-
private T ReadOriginalValue<T>(IProperty property, int originalValueIndex)
827+
/// <summary>
828+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
829+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
830+
/// any release. You should only use it directly in your code with extreme caution and knowing that
831+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
832+
/// </summary>
833+
public T ReadOriginalValue<T>(IProperty property, int originalValueIndex)
834834
=> _originalValues.GetValue<T>(this, property, originalValueIndex);
835835

836836
private static readonly MethodInfo ReadRelationshipSnapshotValueMethod
@@ -842,8 +842,13 @@ private static readonly MethodInfo ReadRelationshipSnapshotValueMethod
842842
internal static MethodInfo MakeReadRelationshipSnapshotValueMethod(Type type)
843843
=> ReadRelationshipSnapshotValueMethod.MakeGenericMethod(type);
844844

845-
[UsedImplicitly]
846-
private T ReadRelationshipSnapshotValue<T>(IPropertyBase propertyBase, int relationshipSnapshotIndex)
845+
/// <summary>
846+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
847+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
848+
/// any release. You should only use it directly in your code with extreme caution and knowing that
849+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
850+
/// </summary>
851+
public T ReadRelationshipSnapshotValue<T>(IPropertyBase propertyBase, int relationshipSnapshotIndex)
847852
=> _relationshipsSnapshot.GetValue<T>(this, propertyBase, relationshipSnapshotIndex);
848853

849854
[UnconditionalSuppressMessage(
@@ -855,21 +860,31 @@ internal static MethodInfo MakeReadStoreGeneratedValueMethod(Type type)
855860
private static readonly MethodInfo ReadStoreGeneratedValueMethod
856861
= typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadStoreGeneratedValue))!;
857862

858-
[UsedImplicitly]
859-
private T ReadStoreGeneratedValue<T>(int storeGeneratedIndex)
863+
/// <summary>
864+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
865+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
866+
/// any release. You should only use it directly in your code with extreme caution and knowing that
867+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
868+
/// </summary>
869+
public T ReadStoreGeneratedValue<T>(int storeGeneratedIndex)
860870
=> _storeGeneratedValues.GetValue<T>(storeGeneratedIndex);
861871

862872
private static readonly MethodInfo ReadTemporaryValueMethod
863-
= typeof(InternalEntityEntry).GetTypeInfo().GetDeclaredMethod(nameof(ReadTemporaryValue))!;
873+
= typeof(InternalEntityEntry).GetMethod(nameof(ReadTemporaryValue))!;
864874

865875
[UnconditionalSuppressMessage(
866876
"ReflectionAnalysis", "IL2060",
867877
Justification = "MakeGenericMethod wrapper, see https://github.com/dotnet/linker/issues/2482")]
868878
internal static MethodInfo MakeReadTemporaryValueMethod(Type type)
869879
=> ReadTemporaryValueMethod.MakeGenericMethod(type);
870880

871-
[UsedImplicitly]
872-
private T ReadTemporaryValue<T>(int storeGeneratedIndex)
881+
/// <summary>
882+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
883+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
884+
/// any release. You should only use it directly in your code with extreme caution and knowing that
885+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
886+
/// </summary>
887+
public T ReadTemporaryValue<T>(int storeGeneratedIndex)
873888
=> _temporaryValues.GetValue<T>(storeGeneratedIndex);
874889

875890
private static readonly MethodInfo GetCurrentValueMethod
@@ -942,7 +957,7 @@ private void WritePropertyValue(
942957

943958
var setter = forMaterialization
944959
? concretePropertyBase.MaterializationSetter
945-
: concretePropertyBase.Setter;
960+
: concretePropertyBase.GetSetter();
946961

947962
setter.SetClrValue(Entity, value);
948963
}
@@ -1124,7 +1139,7 @@ public void EnsureTemporaryValues()
11241139
{
11251140
if (_temporaryValues.IsEmpty)
11261141
{
1127-
_temporaryValues = new SidecarValues(((IRuntimeEntityType)EntityType).TemporaryValuesFactory(this));
1142+
_temporaryValues = new SidecarValues(EntityType.TemporaryValuesFactory(this));
11281143
}
11291144
}
11301145

@@ -1138,7 +1153,7 @@ public void EnsureStoreGeneratedValues()
11381153
{
11391154
if (_storeGeneratedValues.IsEmpty)
11401155
{
1141-
_storeGeneratedValues = new SidecarValues(((IRuntimeEntityType)EntityType).StoreGeneratedValuesFactory());
1156+
_storeGeneratedValues = new SidecarValues(EntityType.StoreGeneratedValuesFactory());
11421157
}
11431158
}
11441159

src/EFCore/ChangeTracking/Internal/SidecarValues.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ private readonly struct SidecarValues
99
{
1010
private readonly ISnapshot _values;
1111

12-
public SidecarValues(ISnapshot valuesFactory)
12+
public SidecarValues(ISnapshot values)
1313
{
14-
_values = valuesFactory;
14+
_values = values;
1515
}
1616

1717
public bool TryGetValue(int index, out object? value)

0 commit comments

Comments
 (0)