Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
24de17d
Merge commit '2fb3ab16a3f71af75e08266ec3c3ffdd7f3794ab'
Jul 21, 2026
001bc03
Merge commit '1f36ba0cdd990dbd64ae35abc3f2edfcc6932684'
Jul 27, 2026
d2d247f
Merge commit '3454802156b3493cf399b7668b1520ca0865b46c'
Aug 3, 2026
2ca5c38
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Aug 3, 2026
2cb719a
Merged PR 63491: [release/8.0] Merge from public
AndriySvyryd Aug 4, 2026
d968058
Merge commit '0e529ddcb0c77f9f46534ffd0d8f48b78dc2070f'
Aug 5, 2026
2ca36a9
Merge commit 'fd223ddcd00e759068f88acb3fc34f550ea92797'
Aug 5, 2026
8b3bdf7
Merge commit '7d2f232b1d4be1ba5c07ec304528b91d257348b3'
Aug 5, 2026
09f3875
Merge commit 'f65d06cf7e72808f7dd1f5b44ecf83479eb2fbfb'
Aug 10, 2026
75200b3
Merge commit '32caad9a403061f5e598cef0329ff415621fcc55'
Aug 11, 2026
06b2df6
Merge commit '12194716e868295f3f1d8c23bdcac25f4ced2ea6'
Aug 11, 2026
621568d
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Aug 12, 2026
4ded4f1
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Aug 12, 2026
5f89ffe
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Aug 13, 2026
bbd3472
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Aug 13, 2026
c8edbfb
Merged PR 63498: [internal/release/8.0] Update dependencies from dnce…
Aug 13, 2026
ec5ad7d
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Aug 13, 2026
e3050de
Merged PR 63894: [internal/release/9.0] Update dependencies from dnce…
Aug 13, 2026
9d948c7
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot Aug 21, 2026
4caf9ee
Merged PR 64302: [internal/release/8.0] Update dependencies from dnce…
Aug 21, 2026
a186e59
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] Sep 7, 2026
bba3c34
Merge commit '4caf9eeca38ab8bbc8857b975a8f0ad29ad2ea7f' into internal…
dotnet-bot Sep 9, 2026
dbe410d
Merge commit 'e3050de15c005dfd3223da1475572044b72a6758' into internal…
dotnet-bot Sep 9, 2026
de781c5
Merging internal commits for release/8.0
AndriySvyryd Sep 9, 2026
c4a06e5
Merging internal commits for release/9.0 (#38940)
AndriySvyryd Sep 9, 2026
afd85d3
[release/9.0]: Bump Microsoft.AspNetCore.Identity.EntityFrameworkCore…
dependabot[bot] Sep 9, 2026
74b797f
[release/9.0]: Bump Microsoft.Azure.Cosmos from 3.62.1 to 3.63.0 (#38…
dependabot[bot] Sep 9, 2026
11651bc
Merge branch 'release/9.0' into merge/release/8.0-to-release/9.0
AndriySvyryd Sep 9, 2026
f2ab284
Merge pull request #38944 from dotnet/merge/release/8.0-to-release/9.0
AndriySvyryd Sep 10, 2026
2b65a86
Update dependencies from build 330600 (#38922)
dotnet-maestro[bot] Sep 10, 2026
8d37357
Merge branch 'release/10.0' into merge/release/9.0-to-release/10.0
wtgodbe Sep 10, 2026
f0515a9
[release/10.0]: Bump Microsoft.Azure.Cosmos from 3.62.1 to 3.63.0 (#3…
dependabot[bot] Sep 10, 2026
d940b2f
Merge pull request #38945 from dotnet/merge/release/9.0-to-release/10.0
AndriySvyryd Sep 11, 2026
d36e00b
Merge branch 'release/11.0' into merge/release/10.0-to-release/11.0
AndriySvyryd Sep 11, 2026
db72249
Discard changes to Directory.Packages.props
AndriySvyryd Sep 11, 2026
82ce89b
Discard changes to NuGet.config
AndriySvyryd Sep 11, 2026
8b99600
[release/11.0] Fix UPDATE ordering regression for unique-index reassi…
Copilot Sep 14, 2026
e989d0e
[release/11.0] Lift mixed outer-reference aggregate arguments (#38925)
Copilot Sep 14, 2026
83e6ef7
[release/11.0] Fix projecting JSON complex collection together with c…
Copilot Sep 14, 2026
2b9be5e
Update dependencies from build 331727 (#38975)
dotnet-maestro[bot] Sep 14, 2026
e3144b6
[release/11.0]: Bump Microsoft.Data.SqlClient from 7.0.2 to 7.0.3 (#3…
dependabot[bot] Sep 14, 2026
bd2cc34
[release/11.0]: Bump Microsoft.Data.SqlClient.Extensions.Azure from 7…
dependabot[bot] Sep 14, 2026
17c442f
[release/11.0]: Bump Microsoft.DotNet.XUnitV3Extensions from 11.0.0-b…
dependabot[bot] Sep 14, 2026
a88fade
[release/11.0]: Bump Microsoft.AspNetCore.Identity.EntityFrameworkCor…
dependabot[bot] Sep 14, 2026
a9d6e93
Merge pull request #38956 from dotnet/merge/release/10.0-to-release/11.0
AndriySvyryd Sep 14, 2026
734a5f7
Merge pull request #38997 from dotnet/darc-release/11.0-07246f3c-4116…
dotnet-maestro[bot] Sep 15, 2026
7d8981c
[release/11.0] Source code updates from dotnet/dotnet (#39003)
dotnet-maestro[bot] Sep 16, 2026
90fcbcc
[release/11.0] Source code updates from dotnet/dotnet (#39007)
dotnet-maestro[bot] Sep 17, 2026
b61f0f8
Merge branch 'main' into merge/release/11.0-to-main
AndriySvyryd Sep 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions eng/common/core-templates/job/helix-job-monitor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,23 @@ parameters:
type: string
default: https://helix.dot.net/

# Helix API access token forwarded to the tool via the HELIX_ACCESSTOKEN environment variable.
# Helix API access token forwarded via HELIX_ACCESSTOKEN. Not forwarded when
# useEntraAuthentication is true.
- name: helixAccessToken
type: string
default: ''

# Use a refreshable Entra credential instead of a PAT or anonymous access.
- name: useEntraAuthentication
type: boolean
default: false

# Azure service connection ID authorized for Helix. Required when
# useEntraAuthentication is true.
- name: azureSubscription
type: string
default: ''

# Polling interval in seconds (--polling-interval-seconds).
- name: pollingIntervalSeconds
type: number
Expand Down Expand Up @@ -141,6 +153,26 @@ jobs:
- checkout: self
fetchDepth: 1

- ${{ if and(eq(parameters.useEntraAuthentication, true), eq(parameters.azureSubscription, '')) }}:
- pwsh: throw "azureSubscription must be set when useEntraAuthentication is true."
displayName: Validate Helix Entra authentication

- ${{ if eq(parameters.useEntraAuthentication, true) }}:
- task: AzureCLI@2
displayName: Initialize Helix Entra authentication
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
addSpnToEnvironment: true
scriptType: pscore
scriptLocation: inlineScript
inlineScript: |
if ([string]::IsNullOrWhiteSpace($env:servicePrincipalId) -or [string]::IsNullOrWhiteSpace($env:tenantId)) {
throw "The Helix Azure service connection did not provide a service principal or tenant ID."
}

Write-Host "##vso[task.setvariable variable=HelixEntraClientId]$env:servicePrincipalId"
Write-Host "##vso[task.setvariable variable=HelixEntraTenantId]$env:tenantId"

- ${{ if ne(parameters.toolNupkgArtifactName, '') }}:
- task: DownloadPipelineArtifact@2
displayName: Download Helix Job Monitor artifact
Expand Down Expand Up @@ -214,6 +246,7 @@ jobs:

toolArgs=(
--helix-base-uri '${{ parameters.helixBaseUri }}'
--use-entra-authentication '${{ parameters.useEntraAuthentication }}'
--polling-interval-seconds '${{ parameters.pollingIntervalSeconds }}'
--fail-on-failed-tests '${{ parameters.failWorkItemsWithFailedTests }}'
--allow-no-helix-jobs '${{ parameters.allowNoHelixJobs }}'
Expand Down Expand Up @@ -275,4 +308,9 @@ jobs:
displayName: Monitor Helix Jobs
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
HELIX_ACCESSTOKEN: ${{ parameters.helixAccessToken }}
${{ if eq(parameters.useEntraAuthentication, false) }}:
HELIX_ACCESSTOKEN: ${{ parameters.helixAccessToken }}
${{ if eq(parameters.useEntraAuthentication, true) }}:
AZURESUBSCRIPTION_CLIENT_ID: $(HelixEntraClientId)
AZURESUBSCRIPTION_TENANT_ID: $(HelixEntraTenantId)
AZURESUBSCRIPTION_SERVICE_CONNECTION_ID: ${{ parameters.azureSubscription }}
43 changes: 39 additions & 4 deletions eng/common/core-templates/steps/send-to-helix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ parameters:
HelixType: 'tests/default/' # required -- Helix telemetry which identifies what type of data this is; should include "test" for clarity and must end in '/'
HelixBuild: $(Build.BuildNumber) # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number
HelixTargetQueues: '' # required -- semicolon-delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues
HelixAccessToken: '' # required -- access token to make Helix API requests; should be provided by the appropriate variable group
HelixAccessToken: '' # optional -- legacy access token; not forwarded when HelixUseEntraAuthentication is true
HelixUseEntraAuthentication: false # optional -- use refreshable Entra authentication instead of a PAT or anonymous access
HelixAzureSubscription: '' # required when HelixUseEntraAuthentication is true -- Azure service connection ID authorized for Helix
HelixProjectPath: 'eng/common/helixpublish.proj' # optional -- path to the project file to build relative to BUILD_SOURCESDIRECTORY
HelixProjectArguments: '' # optional -- arguments passed to the build command
HelixConfiguration: '' # optional -- additional property attached to a job
Expand Down Expand Up @@ -32,12 +34,35 @@ parameters:
continueOnError: false # optional -- determines whether to continue the build if the step errors; defaults to false

steps:
- ${{ if and(eq(parameters.HelixUseEntraAuthentication, true), eq(parameters.HelixAzureSubscription, '')) }}:
- pwsh: throw "HelixAzureSubscription must be set when HelixUseEntraAuthentication is true."
displayName: Validate Helix Entra authentication
condition: ${{ parameters.condition }}

- ${{ if eq(parameters.HelixUseEntraAuthentication, true) }}:
- task: AzureCLI@2
displayName: Initialize Helix Entra authentication
inputs:
azureSubscription: ${{ parameters.HelixAzureSubscription }}
addSpnToEnvironment: true
scriptType: pscore
scriptLocation: inlineScript
inlineScript: |
if ([string]::IsNullOrWhiteSpace($env:servicePrincipalId) -or [string]::IsNullOrWhiteSpace($env:tenantId)) {
throw "The Helix Azure service connection did not provide a service principal or tenant ID."
}

Write-Host "##vso[task.setvariable variable=HelixEntraClientId]$env:servicePrincipalId"
Write-Host "##vso[task.setvariable variable=HelixEntraTenantId]$env:tenantId"
condition: ${{ parameters.condition }}

- powershell: >
$(Build.SourcesDirectory)\eng\common\msbuild.ps1
$(Build.SourcesDirectory)/${{ parameters.HelixProjectPath }}
/restore
/p:TreatWarningsAsErrors=false
/p:EnableHelixJobMonitor=${{ parameters.UseHelixMonitor }}
/p:HelixUseEntraAuthentication=${{ parameters.HelixUseEntraAuthentication }}
${{ parameters.HelixProjectArguments }}
/t:Test
/bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog
Expand All @@ -49,7 +74,12 @@ steps:
HelixBuild: ${{ parameters.HelixBuild }}
HelixConfiguration: ${{ parameters.HelixConfiguration }}
HelixTargetQueues: ${{ parameters.HelixTargetQueues }}
HelixAccessToken: ${{ parameters.HelixAccessToken }}
${{ if eq(parameters.HelixUseEntraAuthentication, false) }}:
HelixAccessToken: ${{ parameters.HelixAccessToken }}
${{ if eq(parameters.HelixUseEntraAuthentication, true) }}:
AZURESUBSCRIPTION_CLIENT_ID: $(HelixEntraClientId)
AZURESUBSCRIPTION_TENANT_ID: $(HelixEntraTenantId)
AZURESUBSCRIPTION_SERVICE_CONNECTION_ID: ${{ parameters.HelixAzureSubscription }}
HelixPreCommands: ${{ parameters.HelixPreCommands }}
HelixPostCommands: ${{ parameters.HelixPostCommands }}
WorkItemDirectory: ${{ parameters.WorkItemDirectory }}
Expand All @@ -76,6 +106,7 @@ steps:
/restore
/p:TreatWarningsAsErrors=false
/p:EnableHelixJobMonitor=${{ parameters.UseHelixMonitor }}
/p:HelixUseEntraAuthentication=${{ parameters.HelixUseEntraAuthentication }}
${{ parameters.HelixProjectArguments }}
/t:Test
/bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog
Expand All @@ -87,7 +118,12 @@ steps:
HelixBuild: ${{ parameters.HelixBuild }}
HelixConfiguration: ${{ parameters.HelixConfiguration }}
HelixTargetQueues: ${{ parameters.HelixTargetQueues }}
HelixAccessToken: ${{ parameters.HelixAccessToken }}
${{ if eq(parameters.HelixUseEntraAuthentication, false) }}:
HelixAccessToken: ${{ parameters.HelixAccessToken }}
${{ if eq(parameters.HelixUseEntraAuthentication, true) }}:
AZURESUBSCRIPTION_CLIENT_ID: $(HelixEntraClientId)
AZURESUBSCRIPTION_TENANT_ID: $(HelixEntraTenantId)
AZURESUBSCRIPTION_SERVICE_CONNECTION_ID: ${{ parameters.HelixAzureSubscription }}
HelixPreCommands: ${{ parameters.HelixPreCommands }}
HelixPostCommands: ${{ parameters.HelixPostCommands }}
WorkItemDirectory: ${{ parameters.WorkItemDirectory }}
Expand All @@ -108,4 +144,3 @@ steps:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT'))
continueOnError: ${{ parameters.continueOnError }}

4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "11.0.100-rc.1.26420.103",
"version": "11.0.100-rc.1.26425.128",
"allowPrerelease": true,
"rollForward": "latestMajor",
"paths": [
Expand All @@ -13,7 +13,7 @@
"runner": "Microsoft.Testing.Platform"
},
"tools": {
"dotnet": "11.0.100-rc.1.26420.103",
"dotnet": "11.0.100-rc.1.26425.128",
"runtimes": {
"dotnet": [
"$(MicrosoftNETCorePlatformsVersion)"
Expand Down
15 changes: 6 additions & 9 deletions src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1277,15 +1277,12 @@ private void AddUniqueValueEdges()
var rowIndexValueFactory = ((TableIndex)index).GetRowIndexValueFactory();
var (value, hasNullValue) = rowIndexValueFactory.CreateEquatableIndexValue(command);

if (command.EntityState == EntityState.Modified)
{
var (originalValue, _) = rowIndexValueFactory.CreateEquatableIndexValue(command, fromOriginalValues: true);
if (Equals(originalValue, value))
{
continue;
}
}

// Note: unlike the predecessor (first) pass above, we don't skip creating an edge here when the
// command's own index value appears unchanged. A predecessor is only ever registered in
// indexPredecessorsMap for a value it is actually releasing (see the check above), so if this
// command's value matches one, it genuinely needs to wait for that release, regardless of whether
// its own current/original value comparison (which can be unreliable, e.g. for attached entities
// whose original value was snapshotted after being modified) suggests no change occurred.
if (value != null)
{
AddMatchingPredecessorEdge(
Expand Down
2 changes: 1 addition & 1 deletion test/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PackageVersion Include="Azure.ResourceManager.CosmosDB" Version="$(AzureResourceManagerCosmosDBVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.20" />
<PackageVersion Include="Microsoft.AspNetCore.OData" Version="9.5.0" />
<PackageVersion Include="Microsoft.Data.SqlClient.Extensions.Azure" Version="7.0.2" />
<PackageVersion Include="Microsoft.Data.SqlClient.Extensions.Azure" Version="7.0.3" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="$(MicrosoftExtensionsConfigurationVersion)" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesVersion)" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="$(MicrosoftExtensionsConfigurationJsonVersion)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,77 @@ public class Blog
public string? Name { get; set; }
}

[Theory, MemberData(nameof(IsAsyncData))] // Issue #38917
public virtual async Task Reassigning_dependent_with_unique_FK_to_attached_entity_orders_updates_correctly(bool async)
{
var contextFactory = await InitializeNonSharedTest<DbContext>(
onModelCreating: mb => mb.Entity<WorkItemGroup38917>()
.HasOne(g => g.Color)
.WithOne(c => c.Group)
.HasForeignKey<RgbColor38917>("GroupId"),
seed: async context =>
{
var group0 = new WorkItemGroup38917 { Name = "G0" };
var group1 = new WorkItemGroup38917 { Name = "G1" };
var color0 = new RgbColor38917 { Id = "0x9a79e4", DisplayName = "red" };
var color1 = new RgbColor38917 { Id = "0xb4e6b9", DisplayName = "turquoise" };

group0.Color = color0;
group1.Color = color1;
context.AddRange(group0, group1);

await context.SaveChangesAsync();
});

await ExecuteWithStrategyInTransactionAsync(
contextFactory,
async context =>
{
var g1 = await context.Set<WorkItemGroup38917>()
.Include(g => g.Color)
.SingleAsync(g => g.Name == "G1");

var c0 = new RgbColor38917 { Id = "0x9a79e4" };
context.Attach(c0);
g1.Color = c0;

if (async)
{
await context.SaveChangesAsync();
}
else
{
context.SaveChanges();
}
},
async context =>
{
var g1 = await context.Set<WorkItemGroup38917>()
.Include(g => g.Color)
.SingleAsync(g => g.Name == "G1");
Assert.Equal("0x9a79e4", g1.Color!.Id);

var g0 = await context.Set<WorkItemGroup38917>()
.Include(g => g.Color)
.SingleAsync(g => g.Name == "G0");
Assert.Null(g0.Color);
});
}

public class WorkItemGroup38917
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; } = "";
public RgbColor38917? Color { get; set; }
}

public class RgbColor38917
{
public string Id { get; set; } = "";
public string? DisplayName { get; set; }
public WorkItemGroup38917? Group { get; set; }
}

[Theory, MemberData(nameof(IsAsyncData))]
public virtual async Task Update_entity_with_not_loaded_property_excludes_column_from_SQL(bool async)
{
Expand Down
47 changes: 47 additions & 0 deletions test/EFCore.Relational.Tests/Update/CommandBatchPreparerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,40 @@ public void BatchCommands_skips_unique_index_edges_for_unchanged_store_generated
Assert.Equal(2, batch.ModificationCommands.Count);
}

[Fact] // Issue #38917
public void BatchCommands_orders_unique_index_release_before_reacquisition_with_unreliable_original_value()
{
var model = CreateModelWithUniqueIndexOnly();
var configuration = CreateContextServices(model);
var stateManager = configuration.GetRequiredService<IStateManager>();

// Releases "Test" by changing UniqueValue away from it. Uses a higher Id than the acquiring entry below so
// that the default (primary-key-based) command ordering alone would produce the wrong (unsafe) order,
// and only the dependency edge asserted by this test can produce the correct order.
var releasingEntry = stateManager.GetOrCreateEntry(
new FakeEntity { Id = 2, UniqueValue = "Other" });
releasingEntry.SetEntityState(EntityState.Modified);
releasingEntry.SetOriginalValue(releasingEntry.EntityType.FindProperty(nameof(FakeEntity.UniqueValue))!, "Test");

// Simulates an attached entity whose original value snapshot ends up matching its (newly assigned) current
// value; it still needs to wait for another command to release "Test" before it can claim it.
var acquiringEntry = stateManager.GetOrCreateEntry(
new FakeEntity { Id = 1, UniqueValue = "Test" });
acquiringEntry.SetEntityState(EntityState.Modified);
acquiringEntry.SetOriginalValue(acquiringEntry.EntityType.FindProperty(nameof(FakeEntity.UniqueValue))!, "Test");

var modelData = new UpdateAdapter(stateManager);

var batches = CreateBatches([acquiringEntry, releasingEntry], modelData);
var batch = Assert.Single(batches);

// The command releasing "Test" must be ordered before the command acquiring it, otherwise we'd get a
// unique constraint violation.
Assert.Equal(
[releasingEntry, acquiringEntry],
batch.ModificationCommands.Select(c => c.Entries.Single()));
}

[Fact]
public void BatchCommands_creates_valid_batch_for_shared_table_added_entities()
{
Expand Down Expand Up @@ -1063,6 +1097,19 @@ private static IModel CreateSimpleFKModel()
return modelBuilder.Model.FinalizeModel();
}

private static IModel CreateModelWithUniqueIndexOnly()
{
var modelBuilder = FakeRelationalTestHelpers.Instance.CreateConventionBuilder();

modelBuilder.Entity<FakeEntity>(b =>
{
b.Ignore(c => c.RelatedId);
b.HasIndex(c => c.UniqueValue).IsUnique();
});

return modelBuilder.Model.FinalizeModel();
}

private static IModel CreateFKOneToManyModelWithGeneratedIds()
{
var modelBuilder = FakeRelationalTestHelpers.Instance.CreateConventionBuilder();
Expand Down
Loading