From 4ef324feb3c86334cc772f35d24356daaf3024e9 Mon Sep 17 00:00:00 2001 From: DotNet Bot Date: Thu, 2 May 2024 05:28:28 +0000 Subject: [PATCH 01/32] [internal/release/8.0] Update dependencies from dnceng/internal/dotnet-runtime --- NuGet.config | 4 ++-- eng/Version.Details.xml | 16 ++++++++-------- eng/Versions.props | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/NuGet.config b/NuGet.config index 1d2f9ecbd85..deca96188ca 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,7 +4,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index bd37246d819..d04dce112af 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -29,9 +29,9 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime 5535e31a712343a63f5d7d796cd874e563e5ac14 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 087e15321bb712ef6fe8b0ba6f8bd12facf92629 + 335917ba819721d6e125010aec85af6e423c7028 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime @@ -41,18 +41,18 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime 9f4b1f5d664afdfc80e1508ab7ed099dff210fbd - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 087e15321bb712ef6fe8b0ba6f8bd12facf92629 + 335917ba819721d6e125010aec85af6e423c7028 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 087e15321bb712ef6fe8b0ba6f8bd12facf92629 + 335917ba819721d6e125010aec85af6e423c7028 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 087e15321bb712ef6fe8b0ba6f8bd12facf92629 + 335917ba819721d6e125010aec85af6e423c7028 diff --git a/eng/Versions.props b/eng/Versions.props index 1dd1f03be8d..9c589aaa7d9 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,12 +24,12 @@ 8.0.0 8.0.0 8.0.0 - 8.0.5-servicing.24216.15 + 8.0.6-servicing.24251.11 8.0.0 8.0.3 - 8.0.5 - 8.0.5 - 8.0.5-servicing.24216.15 + 8.0.6 + 8.0.6 + 8.0.6-servicing.24251.11 8.0.0-beta.24204.3 From e7dd3499b9a52a333343e66915ae15c8bcc97b9f Mon Sep 17 00:00:00 2001 From: DotNet Bot Date: Fri, 3 May 2024 12:32:26 +0000 Subject: [PATCH 02/32] [internal/release/8.0] Update dependencies from dnceng/internal/dotnet-runtime --- NuGet.config | 4 ++-- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/NuGet.config b/NuGet.config index deca96188ca..f18653c063b 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,7 +4,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d04dce112af..3319e264594 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -29,9 +29,9 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime 5535e31a712343a63f5d7d796cd874e563e5ac14 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 335917ba819721d6e125010aec85af6e423c7028 + 0e1c3efd9f2bf3e1d7c96866b383650310d5dec1 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime @@ -43,16 +43,16 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 335917ba819721d6e125010aec85af6e423c7028 + 0e1c3efd9f2bf3e1d7c96866b383650310d5dec1 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 335917ba819721d6e125010aec85af6e423c7028 + 0e1c3efd9f2bf3e1d7c96866b383650310d5dec1 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 335917ba819721d6e125010aec85af6e423c7028 + 0e1c3efd9f2bf3e1d7c96866b383650310d5dec1 diff --git a/eng/Versions.props b/eng/Versions.props index 9c589aaa7d9..ddfe9f812ca 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,12 +24,12 @@ 8.0.0 8.0.0 8.0.0 - 8.0.6-servicing.24251.11 + 8.0.6-servicing.24253.2 8.0.0 8.0.3 8.0.6 8.0.6 - 8.0.6-servicing.24251.11 + 8.0.6-servicing.24253.2 8.0.0-beta.24204.3 From 79322f37015c26b5dc05bee854fcdac1e7042b58 Mon Sep 17 00:00:00 2001 From: DotNet Bot Date: Fri, 3 May 2024 20:38:57 +0000 Subject: [PATCH 03/32] [internal/release/8.0] Update dependencies from dnceng/internal/dotnet-runtime --- NuGet.config | 4 ++-- eng/Version.Details.xml | 20 ++++++++++---------- eng/Versions.props | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/NuGet.config b/NuGet.config index f18653c063b..a9e2b96ee51 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,7 +4,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3319e264594..4104b671319 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -25,34 +25,34 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime 5535e31a712343a63f5d7d796cd874e563e5ac14 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 5535e31a712343a63f5d7d796cd874e563e5ac14 + fa5b0d8f4a8b424732cc992158aa92842f8a2846 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 0e1c3efd9f2bf3e1d7c96866b383650310d5dec1 + fa5b0d8f4a8b424732cc992158aa92842f8a2846 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime 5535e31a712343a63f5d7d796cd874e563e5ac14 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 9f4b1f5d664afdfc80e1508ab7ed099dff210fbd + fa5b0d8f4a8b424732cc992158aa92842f8a2846 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 0e1c3efd9f2bf3e1d7c96866b383650310d5dec1 + fa5b0d8f4a8b424732cc992158aa92842f8a2846 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 0e1c3efd9f2bf3e1d7c96866b383650310d5dec1 + fa5b0d8f4a8b424732cc992158aa92842f8a2846 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 0e1c3efd9f2bf3e1d7c96866b383650310d5dec1 + fa5b0d8f4a8b424732cc992158aa92842f8a2846 diff --git a/eng/Versions.props b/eng/Versions.props index ddfe9f812ca..f3005645356 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -23,13 +23,13 @@ 8.0.0 8.0.0 8.0.0 - 8.0.0 - 8.0.6-servicing.24253.2 + 8.0.1 + 8.0.6-servicing.24253.6 8.0.0 - 8.0.3 + 8.0.4 8.0.6 8.0.6 - 8.0.6-servicing.24253.2 + 8.0.6-servicing.24253.6 8.0.0-beta.24204.3 From b3a7017957b0f21a0fb5ff610b708319f5a71b5a Mon Sep 17 00:00:00 2001 From: DotNet Bot Date: Sat, 18 May 2024 02:08:12 +0000 Subject: [PATCH 04/32] [internal/release/8.0] Update dependencies from dnceng/internal/dotnet-runtime --- NuGet.config | 4 ++-- eng/Version.Details.xml | 20 ++++++++++---------- eng/Versions.props | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/NuGet.config b/NuGet.config index a9e2b96ee51..0943fcec51e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,7 +4,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4104b671319..46aaf312374 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -27,11 +27,11 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - fa5b0d8f4a8b424732cc992158aa92842f8a2846 + cb4ec67fd1784497c953f65bfc390eb8bfdf6c6b - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - fa5b0d8f4a8b424732cc992158aa92842f8a2846 + cb4ec67fd1784497c953f65bfc390eb8bfdf6c6b https://dev.azure.com/dnceng/internal/_git/dotnet-runtime @@ -39,20 +39,20 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - fa5b0d8f4a8b424732cc992158aa92842f8a2846 + cb4ec67fd1784497c953f65bfc390eb8bfdf6c6b - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - fa5b0d8f4a8b424732cc992158aa92842f8a2846 + cb4ec67fd1784497c953f65bfc390eb8bfdf6c6b - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - fa5b0d8f4a8b424732cc992158aa92842f8a2846 + cb4ec67fd1784497c953f65bfc390eb8bfdf6c6b - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - fa5b0d8f4a8b424732cc992158aa92842f8a2846 + cb4ec67fd1784497c953f65bfc390eb8bfdf6c6b diff --git a/eng/Versions.props b/eng/Versions.props index 5c2a988007d..59bd4481aa8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,12 +24,12 @@ 8.0.0 8.0.0 8.0.1 - 8.0.6-servicing.24253.6 + 8.0.7-servicing.24267.24 8.0.0 8.0.4 - 8.0.6 - 8.0.6 - 8.0.6-servicing.24253.6 + 8.0.7 + 8.0.7 + 8.0.7-servicing.24267.24 8.0.0-beta.24204.3 From e60bce54547ab8c7f4238d46ad43a49d289d9c76 Mon Sep 17 00:00:00 2001 From: DotNet Bot Date: Mon, 20 May 2024 23:58:43 +0000 Subject: [PATCH 05/32] [internal/release/8.0] Update dependencies from dnceng/internal/dotnet-runtime --- NuGet.config | 4 ++-- eng/Version.Details.xml | 16 ++++++++-------- eng/Versions.props | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/NuGet.config b/NuGet.config index 0943fcec51e..9d5b0f280ee 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,7 +4,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2c54b6e6c5f..5d82dec1aaa 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -27,11 +27,11 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - cb4ec67fd1784497c953f65bfc390eb8bfdf6c6b + 6d230cdb65dee13db6779749580d02bcd413af70 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - cb4ec67fd1784497c953f65bfc390eb8bfdf6c6b + 6d230cdb65dee13db6779749580d02bcd413af70 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime @@ -39,20 +39,20 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - cb4ec67fd1784497c953f65bfc390eb8bfdf6c6b + 6d230cdb65dee13db6779749580d02bcd413af70 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - cb4ec67fd1784497c953f65bfc390eb8bfdf6c6b + 6d230cdb65dee13db6779749580d02bcd413af70 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - cb4ec67fd1784497c953f65bfc390eb8bfdf6c6b + 6d230cdb65dee13db6779749580d02bcd413af70 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - cb4ec67fd1784497c953f65bfc390eb8bfdf6c6b + 6d230cdb65dee13db6779749580d02bcd413af70 diff --git a/eng/Versions.props b/eng/Versions.props index 6b5c924a568..d6e5ff2ea92 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,12 +24,12 @@ 8.0.0 8.0.0 8.0.1 - 8.0.7-servicing.24267.24 + 8.0.7-servicing.24270.7 8.0.0 8.0.4 8.0.7 8.0.7 - 8.0.7-servicing.24267.24 + 8.0.7-servicing.24270.7 8.0.0-beta.24266.3 From b983f69af699b9337b81152f32799ecaf262d34f Mon Sep 17 00:00:00 2001 From: DotNet-Bot Date: Tue, 21 May 2024 01:52:57 +0000 Subject: [PATCH 06/32] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-runtime build 20240520.14 Microsoft.Extensions.DependencyModel , Microsoft.Extensions.HostFactoryResolver.Sources , Microsoft.NETCore.App.Ref , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.BrowserDebugHost.Transport , System.Text.Json From Version 8.0.1 -> To Version 8.0.1 --- NuGet.config | 4 ++-- eng/Version.Details.xml | 16 ++++++++-------- eng/Versions.props | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/NuGet.config b/NuGet.config index 9d5b0f280ee..bbca623e149 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,7 +4,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 5d82dec1aaa..ac10a1249cb 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -27,11 +27,11 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 6d230cdb65dee13db6779749580d02bcd413af70 + 63d80966a9f0d15e057d0d146702405b19c82533 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 6d230cdb65dee13db6779749580d02bcd413af70 + 63d80966a9f0d15e057d0d146702405b19c82533 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime @@ -39,20 +39,20 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 6d230cdb65dee13db6779749580d02bcd413af70 + 63d80966a9f0d15e057d0d146702405b19c82533 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 6d230cdb65dee13db6779749580d02bcd413af70 + 63d80966a9f0d15e057d0d146702405b19c82533 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 6d230cdb65dee13db6779749580d02bcd413af70 + 63d80966a9f0d15e057d0d146702405b19c82533 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 6d230cdb65dee13db6779749580d02bcd413af70 + 63d80966a9f0d15e057d0d146702405b19c82533 diff --git a/eng/Versions.props b/eng/Versions.props index d6e5ff2ea92..c74edb5c891 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,12 +24,12 @@ 8.0.0 8.0.0 8.0.1 - 8.0.7-servicing.24270.7 + 8.0.7-servicing.24270.14 8.0.0 8.0.4 8.0.7 8.0.7 - 8.0.7-servicing.24270.7 + 8.0.7-servicing.24270.14 8.0.0-beta.24266.3 From 7b638e5601fef91e2baf5c52a3f3f9b89903cff2 Mon Sep 17 00:00:00 2001 From: DotNet Bot Date: Wed, 12 Jun 2024 00:46:57 +0000 Subject: [PATCH 07/32] [internal/release/8.0] Update dependencies from dnceng/internal/dotnet-runtime --- NuGet.config | 4 ++-- eng/Version.Details.xml | 16 ++++++++-------- eng/Versions.props | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/NuGet.config b/NuGet.config index bbca623e149..7e9bec9d4a9 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,7 +4,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ac10a1249cb..85352d7f702 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -27,11 +27,11 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 63d80966a9f0d15e057d0d146702405b19c82533 + e0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 63d80966a9f0d15e057d0d146702405b19c82533 + e0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d https://dev.azure.com/dnceng/internal/_git/dotnet-runtime @@ -39,20 +39,20 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 63d80966a9f0d15e057d0d146702405b19c82533 + e0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 63d80966a9f0d15e057d0d146702405b19c82533 + e0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 63d80966a9f0d15e057d0d146702405b19c82533 + e0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 63d80966a9f0d15e057d0d146702405b19c82533 + e0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d diff --git a/eng/Versions.props b/eng/Versions.props index c74edb5c891..b2163f278fa 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,12 +24,12 @@ 8.0.0 8.0.0 8.0.1 - 8.0.7-servicing.24270.14 + 8.0.7-servicing.24311.13 8.0.0 8.0.4 8.0.7 8.0.7 - 8.0.7-servicing.24270.14 + 8.0.7-servicing.24311.13 8.0.0-beta.24266.3 From 368f641f08739d9f741cb077bf953f0adf3a4469 Mon Sep 17 00:00:00 2001 From: DotNet Bot Date: Thu, 13 Jun 2024 15:17:22 +0000 Subject: [PATCH 08/32] Merged PR 40368: [internal/release/8.0] Update dependencies from dnceng/internal/dotnet-runtime This pull request updates the following dependencies [marker]: <> (Begin:922981e1-18b6-46aa-2468-08dbd53ba9ce) ## From https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - **Subscription**: 922981e1-18b6-46aa-2468-08dbd53ba9ce - **Build**: 20240612.14 - **Date Produced**: June 13, 2024 1:29:09 PM UTC - **Commit**: cc6880ce36d783678284d36e8397fc30fda93c8a - **Branch**: refs/heads/internal/release/8.0 [DependencyUpdate]: <> (Begin) - **Updates**: - **Microsoft.Extensions.DependencyModel**: [from 8.0.1 to 8.0.1][1] - **Microsoft.Extensions.HostFactoryResolver.Sources**: [from 8.0.7-servicing.24311.13 to 8.0.7-servicing.24312.14][1] - **Microsoft.NETCore.App.Ref**: [from 8.0.7 to 8.0.7][1] - **Microsoft.NETCore.App.Runtime.win-x64**: [from 8.0.7 to 8.0.7][1] - **Microsoft.NETCore.BrowserDebugHost.Transport**: [from 8.0.7-servicing.24311.13 to 8.0.7-servicing.24312.14][1] - **System.Text.Json**: [from 8.0.4 to 8.0.4][1] [1]: https://dev.azure.com/dnceng/internal/_git/dotnet-runtime/branches?baseVersion=GCe0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d&targetVersion=GCcc6880ce36d783678284d36e8397fc30fda93c8a&_a=files [DependencyUpdate]: <> (End) [marker]: <> (End:922981e1-18b6-46aa-2468-08dbd53ba9ce) --- NuGet.config | 4 ++-- eng/Version.Details.xml | 16 ++++++++-------- eng/Versions.props | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/NuGet.config b/NuGet.config index 7e9bec9d4a9..386d9ed1b67 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,7 +4,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 85352d7f702..a533b51aa91 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -27,11 +27,11 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - e0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d + cc6880ce36d783678284d36e8397fc30fda93c8a - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - e0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d + cc6880ce36d783678284d36e8397fc30fda93c8a https://dev.azure.com/dnceng/internal/_git/dotnet-runtime @@ -39,20 +39,20 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - e0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d + cc6880ce36d783678284d36e8397fc30fda93c8a https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - e0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d + cc6880ce36d783678284d36e8397fc30fda93c8a https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - e0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d + cc6880ce36d783678284d36e8397fc30fda93c8a - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - e0b6a8149721f5d4f4bc8fe2ae8d39543a503b1d + cc6880ce36d783678284d36e8397fc30fda93c8a diff --git a/eng/Versions.props b/eng/Versions.props index 3b6190757bb..5ac3a5f92db 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,12 +24,12 @@ 8.0.0 8.0.0 8.0.1 - 8.0.7-servicing.24311.13 + 8.0.7-servicing.24312.14 8.0.0 8.0.4 8.0.7 8.0.7 - 8.0.7-servicing.24311.13 + 8.0.7-servicing.24312.14 8.0.0-beta.24266.3 From 7ed2261e7d203ae584586e976898b8e294c18b54 Mon Sep 17 00:00:00 2001 From: DotNet-Bot Date: Fri, 14 Jun 2024 00:28:33 +0000 Subject: [PATCH 09/32] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-runtime build 20240613.11 Microsoft.Extensions.DependencyModel , Microsoft.Extensions.HostFactoryResolver.Sources , Microsoft.NETCore.App.Ref , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.BrowserDebugHost.Transport , System.Text.Json From Version 8.0.1 -> To Version 8.0.1 --- NuGet.config | 4 ++-- eng/Version.Details.xml | 16 ++++++++-------- eng/Versions.props | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/NuGet.config b/NuGet.config index 386d9ed1b67..dab9b098681 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,7 +4,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a533b51aa91..076289d8c69 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -27,11 +27,11 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - cc6880ce36d783678284d36e8397fc30fda93c8a + 2aade6beb02ea367fd97c4070a4198802fe61c03 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - cc6880ce36d783678284d36e8397fc30fda93c8a + 2aade6beb02ea367fd97c4070a4198802fe61c03 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime @@ -39,20 +39,20 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - cc6880ce36d783678284d36e8397fc30fda93c8a + 2aade6beb02ea367fd97c4070a4198802fe61c03 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - cc6880ce36d783678284d36e8397fc30fda93c8a + 2aade6beb02ea367fd97c4070a4198802fe61c03 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - cc6880ce36d783678284d36e8397fc30fda93c8a + 2aade6beb02ea367fd97c4070a4198802fe61c03 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - cc6880ce36d783678284d36e8397fc30fda93c8a + 2aade6beb02ea367fd97c4070a4198802fe61c03 diff --git a/eng/Versions.props b/eng/Versions.props index 5ac3a5f92db..d306f41c701 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,12 +24,12 @@ 8.0.0 8.0.0 8.0.1 - 8.0.7-servicing.24312.14 + 8.0.7-servicing.24313.11 8.0.0 8.0.4 8.0.7 8.0.7 - 8.0.7-servicing.24312.14 + 8.0.7-servicing.24313.11 8.0.0-beta.24266.3 From 5601c26b5f4361c89f5c90d81ae5b3f8800f5360 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Tue, 2 Jul 2024 15:04:57 -0700 Subject: [PATCH 10/32] [release/8.0] Update image to macOS-12 (#34037) --- azure-pipelines-public.yml | 2 +- eng/helix.proj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines-public.yml b/azure-pipelines-public.yml index aa704ddcde6..f4436166dc3 100644 --- a/azure-pipelines-public.yml +++ b/azure-pipelines-public.yml @@ -176,7 +176,7 @@ stages: - job: macOS enablePublishTestResults: true pool: - vmImage: macOS-11 + vmImage: macOS-12 variables: # Rely on task Arcade injects, not auto-injected build step. - skipComponentGovernanceDetection: true diff --git a/eng/helix.proj b/eng/helix.proj index fce3e5c0614..c0f654f9467 100644 --- a/eng/helix.proj +++ b/eng/helix.proj @@ -17,7 +17,7 @@ - Windows.10.Amd64.Open;Ubuntu.1804.Amd64.Open;OSX.1100.Amd64.Open;Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-sqlserver-amd64 + Windows.10.Amd64.Open;OSX.1200.Amd64.Open;Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-sqlserver-amd64 false efcore/localbuild/ t001 From 01b0cf44a3a1f1cd242781a5d319e90e34949a22 Mon Sep 17 00:00:00 2001 From: vseanreesermsft <78103370+vseanreesermsft@users.noreply.github.com> Date: Tue, 2 Jul 2024 17:59:24 -0700 Subject: [PATCH 11/32] Update branding to 8.0.8 (#34141) --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index c004959dcd5..aab4172288a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,6 +1,6 @@ - 8.0.7 + 8.0.8 servicing From 38a1ea20451f0891ad576a879a37ac67dd96a380 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2024 18:14:12 +0000 Subject: [PATCH 12/32] Update dependencies from https://github.com/dotnet/arcade build 20240710.5 (#34209) [release/8.0] Update dependencies from dotnet/arcade --- NuGet.config | 8 ++++ eng/Version.Details.xml | 12 +++--- eng/Versions.props | 2 +- eng/common/post-build/publish-using-darc.ps1 | 15 +++---- .../job/publish-build-assets.yml | 21 +++++---- .../templates-official/job/source-build.yml | 8 ++++ .../job/source-index-stage1.yml | 16 +++---- .../templates-official/jobs/source-build.yml | 8 ++++ .../post-build/post-build.yml | 8 ++-- .../steps/enable-internal-runtimes.yml | 28 ++++++++++++ .../steps/get-delegation-sas.yml | 43 +++++++++++++++++++ .../steps/get-federated-access-token.yml | 28 ++++++++++++ .../templates/job/publish-build-assets.yml | 21 +++++---- eng/common/templates/job/source-build.yml | 8 ++++ .../templates/job/source-index-stage1.yml | 11 ++--- eng/common/templates/jobs/source-build.yml | 8 ++++ .../templates/post-build/post-build.yml | 8 ++-- .../post-build/setup-maestro-vars.yml | 28 ++++++------ .../steps/enable-internal-runtimes.yml | 28 ++++++++++++ .../templates/steps/get-delegation-sas.yml | 43 +++++++++++++++++++ .../steps/get-federated-access-token.yml | 28 ++++++++++++ global.json | 4 +- 22 files changed, 315 insertions(+), 69 deletions(-) create mode 100644 eng/common/templates-official/steps/enable-internal-runtimes.yml create mode 100644 eng/common/templates-official/steps/get-delegation-sas.yml create mode 100644 eng/common/templates-official/steps/get-federated-access-token.yml create mode 100644 eng/common/templates/steps/enable-internal-runtimes.yml create mode 100644 eng/common/templates/steps/get-delegation-sas.yml create mode 100644 eng/common/templates/steps/get-federated-access-token.yml diff --git a/NuGet.config b/NuGet.config index dab9b098681..bd03eeba24f 100644 --- a/NuGet.config +++ b/NuGet.config @@ -5,6 +5,10 @@ + + + + @@ -19,6 +23,10 @@ + + + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 076289d8c69..00602e05fa3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -56,17 +56,17 @@ - + https://github.com/dotnet/arcade - e6f70c7dd528f05cd28cec2a179d58c22e91d9ac + c9efa535175049eb9cba06cae1f8c3d5dbe768a9 - + https://github.com/dotnet/arcade - e6f70c7dd528f05cd28cec2a179d58c22e91d9ac + c9efa535175049eb9cba06cae1f8c3d5dbe768a9 - + https://github.com/dotnet/arcade - e6f70c7dd528f05cd28cec2a179d58c22e91d9ac + c9efa535175049eb9cba06cae1f8c3d5dbe768a9 diff --git a/eng/Versions.props b/eng/Versions.props index 90ce75440fd..4746f670b8d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -32,7 +32,7 @@ 8.0.7-servicing.24313.11 - 8.0.0-beta.24266.3 + 8.0.0-beta.24360.5 diff --git a/eng/common/post-build/publish-using-darc.ps1 b/eng/common/post-build/publish-using-darc.ps1 index 5a3a32ea8d7..238945cb5ab 100644 --- a/eng/common/post-build/publish-using-darc.ps1 +++ b/eng/common/post-build/publish-using-darc.ps1 @@ -2,7 +2,6 @@ param( [Parameter(Mandatory=$true)][int] $BuildId, [Parameter(Mandatory=$true)][int] $PublishingInfraVersion, [Parameter(Mandatory=$true)][string] $AzdoToken, - [Parameter(Mandatory=$true)][string] $MaestroToken, [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro.dot.net', [Parameter(Mandatory=$true)][string] $WaitPublishingFinish, [Parameter(Mandatory=$false)][string] $ArtifactsPublishingAdditionalParameters, @@ -31,13 +30,13 @@ try { } & $darc add-build-to-channel ` - --id $buildId ` - --publishing-infra-version $PublishingInfraVersion ` - --default-channels ` - --source-branch main ` - --azdev-pat $AzdoToken ` - --bar-uri $MaestroApiEndPoint ` - --password $MaestroToken ` + --id $buildId ` + --publishing-infra-version $PublishingInfraVersion ` + --default-channels ` + --source-branch main ` + --azdev-pat "$AzdoToken" ` + --bar-uri "$MaestroApiEndPoint" ` + --ci ` @optionalParams if ($LastExitCode -ne 0) { diff --git a/eng/common/templates-official/job/publish-build-assets.yml b/eng/common/templates-official/job/publish-build-assets.yml index 589ac80a18b..ba3e7df8158 100644 --- a/eng/common/templates-official/job/publish-build-assets.yml +++ b/eng/common/templates-official/job/publish-build-assets.yml @@ -76,13 +76,16 @@ jobs: - task: NuGetAuthenticate@1 - - task: PowerShell@2 + - task: AzureCLI@2 displayName: Publish Build Assets inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet + azureSubscription: "Darc: Maestro Production" + scriptType: ps + scriptLocation: scriptPath + scriptPath: $(Build.SourcesDirectory)/eng/common/sdk-task.ps1 + arguments: > + -task PublishBuildAssets -restore -msbuildEngine dotnet /p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests' - /p:BuildAssetRegistryToken=$(MaestroAccessToken) /p:MaestroApiEndpoint=https://maestro-prod.westus2.cloudapp.azure.com /p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }} /p:OfficialBuildId=$(Build.BuildNumber) @@ -137,14 +140,16 @@ jobs: BARBuildId: ${{ parameters.BARBuildId }} PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - task: PowerShell@2 + - task: AzureCLI@2 displayName: Publish Using Darc inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) + azureSubscription: "Darc: Maestro Production" + scriptType: ps + scriptLocation: scriptPath + scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 + arguments: -BuildId $(BARBuildId) -PublishingInfraVersion 3 -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' - -MaestroToken '$(MaestroApiAccessToken)' -WaitPublishingFinish true -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/templates-official/job/source-build.yml b/eng/common/templates-official/job/source-build.yml index f193dfbe236..f983033bb02 100644 --- a/eng/common/templates-official/job/source-build.yml +++ b/eng/common/templates-official/job/source-build.yml @@ -31,6 +31,12 @@ parameters: # container and pool. platform: {} + # If set to true and running on a non-public project, + # Internal blob storage locations will be enabled. + # This is not enabled by default because many repositories do not need internal sources + # and do not need to have the required service connections approved in the pipeline. + enableInternalSources: false + jobs: - job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }} displayName: Source-Build (${{ parameters.platform.name }}) @@ -62,6 +68,8 @@ jobs: clean: all steps: + - ${{ if eq(parameters.enableInternalSources, true) }}: + - template: /eng/common/templates-official/steps/enable-internal-runtimes.yml - template: /eng/common/templates-official/steps/source-build.yml parameters: platform: ${{ parameters.platform }} diff --git a/eng/common/templates-official/job/source-index-stage1.yml b/eng/common/templates-official/job/source-index-stage1.yml index 43ee0c202fc..60dfb6b2d1c 100644 --- a/eng/common/templates-official/job/source-index-stage1.yml +++ b/eng/common/templates-official/job/source-index-stage1.yml @@ -23,7 +23,7 @@ jobs: value: ${{ parameters.sourceIndexPackageSource }} - name: BinlogPath value: ${{ parameters.binlogPath }} - - template: /eng/common/templates/variables/pool-providers.yml + - template: /eng/common/templates-official/variables/pool-providers.yml ${{ if ne(parameters.pool, '') }}: pool: ${{ parameters.pool }} @@ -34,7 +34,8 @@ jobs: demands: ImageOverride -equals windows.vs2019.amd64.open ${{ if eq(variables['System.TeamProject'], 'internal') }}: name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 + image: windows.vs2022.amd64 + os: windows steps: - ${{ each preStep in parameters.preSteps }}: @@ -70,16 +71,13 @@ jobs: scriptType: 'ps' scriptLocation: 'inlineScript' inlineScript: | - echo "##vso[task.setvariable variable=ARM_CLIENT_ID]$env:servicePrincipalId" - echo "##vso[task.setvariable variable=ARM_ID_TOKEN]$env:idToken" - echo "##vso[task.setvariable variable=ARM_TENANT_ID]$env:tenantId" + echo "##vso[task.setvariable variable=ARM_CLIENT_ID;issecret=true]$env:servicePrincipalId" + echo "##vso[task.setvariable variable=ARM_ID_TOKEN;issecret=true]$env:idToken" + echo "##vso[task.setvariable variable=ARM_TENANT_ID;issecret=true]$env:tenantId" - script: | - echo "Client ID: $(ARM_CLIENT_ID)" - echo "ID Token: $(ARM_ID_TOKEN)" - echo "Tenant ID: $(ARM_TENANT_ID)" az login --service-principal -u $(ARM_CLIENT_ID) --tenant $(ARM_TENANT_ID) --allow-no-subscriptions --federated-token $(ARM_ID_TOKEN) displayName: "Login to Azure" - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) -s netsourceindexstage1 -b stage1 - displayName: Upload stage1 artifacts to source index \ No newline at end of file + displayName: Upload stage1 artifacts to source index diff --git a/eng/common/templates-official/jobs/source-build.yml b/eng/common/templates-official/jobs/source-build.yml index 08e5db9bb11..5cf6a269c0b 100644 --- a/eng/common/templates-official/jobs/source-build.yml +++ b/eng/common/templates-official/jobs/source-build.yml @@ -21,6 +21,12 @@ parameters: # one job runs on 'defaultManagedPlatform'. platforms: [] + # If set to true and running on a non-public project, + # Internal nuget and blob storage locations will be enabled. + # This is not enabled by default because many repositories do not need internal sources + # and do not need to have the required service connections approved in the pipeline. + enableInternalSources: false + jobs: - ${{ if ne(parameters.allCompletedJobId, '') }}: @@ -38,9 +44,11 @@ jobs: parameters: jobNamePrefix: ${{ parameters.jobNamePrefix }} platform: ${{ platform }} + enableInternalSources: ${{ parameters.enableInternalSources }} - ${{ if eq(length(parameters.platforms), 0) }}: - template: /eng/common/templates-official/job/source-build.yml parameters: jobNamePrefix: ${{ parameters.jobNamePrefix }} platform: ${{ parameters.defaultManagedPlatform }} + enableInternalSources: ${{ parameters.enableInternalSources }} diff --git a/eng/common/templates-official/post-build/post-build.yml b/eng/common/templates-official/post-build/post-build.yml index da1f40958b4..0dfa387e7b7 100644 --- a/eng/common/templates-official/post-build/post-build.yml +++ b/eng/common/templates-official/post-build/post-build.yml @@ -272,14 +272,16 @@ stages: - task: NuGetAuthenticate@1 - - task: PowerShell@2 + - task: AzureCLI@2 displayName: Publish Using Darc inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 + azureSubscription: "Darc: Maestro Production" + scriptType: ps + scriptLocation: scriptPath + scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 arguments: -BuildId $(BARBuildId) -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' - -MaestroToken '$(MaestroApiAccessToken)' -WaitPublishingFinish true -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/templates-official/steps/enable-internal-runtimes.yml b/eng/common/templates-official/steps/enable-internal-runtimes.yml new file mode 100644 index 00000000000..93a8394a666 --- /dev/null +++ b/eng/common/templates-official/steps/enable-internal-runtimes.yml @@ -0,0 +1,28 @@ +# Obtains internal runtime download credentials and populates the 'dotnetbuilds-internal-container-read-token-base64' +# variable with the base64-encoded SAS token, by default + +parameters: +- name: federatedServiceConnection + type: string + default: 'dotnetbuilds-internal-read' +- name: outputVariableName + type: string + default: 'dotnetbuilds-internal-container-read-token-base64' +- name: expiryInHours + type: number + default: 1 +- name: base64Encode + type: boolean + default: true + +steps: +- ${{ if ne(variables['System.TeamProject'], 'public') }}: + - template: /eng/common/templates-official/steps/get-delegation-sas.yml + parameters: + federatedServiceConnection: ${{ parameters.federatedServiceConnection }} + outputVariableName: ${{ parameters.outputVariableName }} + expiryInHours: ${{ parameters.expiryInHours }} + base64Encode: ${{ parameters.base64Encode }} + storageAccount: dotnetbuilds + container: internal + permissions: rl diff --git a/eng/common/templates-official/steps/get-delegation-sas.yml b/eng/common/templates-official/steps/get-delegation-sas.yml new file mode 100644 index 00000000000..c0e8f91317f --- /dev/null +++ b/eng/common/templates-official/steps/get-delegation-sas.yml @@ -0,0 +1,43 @@ +parameters: +- name: federatedServiceConnection + type: string +- name: outputVariableName + type: string +- name: expiryInHours + type: number + default: 1 +- name: base64Encode + type: boolean + default: false +- name: storageAccount + type: string +- name: container + type: string +- name: permissions + type: string + default: 'rl' + +steps: +- task: AzureCLI@2 + displayName: 'Generate delegation SAS Token for ${{ parameters.storageAccount }}/${{ parameters.container }}' + inputs: + azureSubscription: ${{ parameters.federatedServiceConnection }} + scriptType: 'pscore' + scriptLocation: 'inlineScript' + inlineScript: | + # Calculate the expiration of the SAS token and convert to UTC + $expiry = (Get-Date).AddHours(${{ parameters.expiryInHours }}).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") + + $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv + + if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to generate SAS token." + exit 1 + } + + if ('${{ parameters.base64Encode }}' -eq 'true') { + $sas = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($sas)) + } + + Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value" + Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true]$sas" diff --git a/eng/common/templates-official/steps/get-federated-access-token.yml b/eng/common/templates-official/steps/get-federated-access-token.yml new file mode 100644 index 00000000000..e3786cef6df --- /dev/null +++ b/eng/common/templates-official/steps/get-federated-access-token.yml @@ -0,0 +1,28 @@ +parameters: +- name: federatedServiceConnection + type: string +- name: outputVariableName + type: string +# Resource to get a token for. Common values include: +# - '499b84ac-1321-427f-aa17-267ca6975798' for Azure DevOps +# - 'https://storage.azure.com/' for storage +# Defaults to Azure DevOps +- name: resource + type: string + default: '499b84ac-1321-427f-aa17-267ca6975798' + +steps: +- task: AzureCLI@2 + displayName: 'Getting federated access token for feeds' + inputs: + azureSubscription: ${{ parameters.federatedServiceConnection }} + scriptType: 'pscore' + scriptLocation: 'inlineScript' + inlineScript: | + $accessToken = az account get-access-token --query accessToken --resource ${{ parameters.resource }} --output tsv + if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to get access token for resource '${{ parameters.resource }}'" + exit 1 + } + Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value" + Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true]$accessToken" diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml index 8ec0151def2..57a41f0a3e1 100644 --- a/eng/common/templates/job/publish-build-assets.yml +++ b/eng/common/templates/job/publish-build-assets.yml @@ -74,13 +74,16 @@ jobs: - task: NuGetAuthenticate@1 - - task: PowerShell@2 + - task: AzureCLI@2 displayName: Publish Build Assets inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet + azureSubscription: "Darc: Maestro Production" + scriptType: ps + scriptLocation: scriptPath + scriptPath: $(Build.SourcesDirectory)/eng/common/sdk-task.ps1 + arguments: > + -task PublishBuildAssets -restore -msbuildEngine dotnet /p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests' - /p:BuildAssetRegistryToken=$(MaestroAccessToken) /p:MaestroApiEndpoint=https://maestro.dot.net /p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }} /p:OfficialBuildId=$(Build.BuildNumber) @@ -133,14 +136,16 @@ jobs: BARBuildId: ${{ parameters.BARBuildId }} PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - task: PowerShell@2 + - task: AzureCLI@2 displayName: Publish Using Darc inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) + azureSubscription: "Darc: Maestro Production" + scriptType: ps + scriptLocation: scriptPath + scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 + arguments: -BuildId $(BARBuildId) -PublishingInfraVersion 3 -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' - -MaestroToken '$(MaestroApiAccessToken)' -WaitPublishingFinish true -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/templates/job/source-build.yml b/eng/common/templates/job/source-build.yml index 8a3deef2b72..c0ff472b697 100644 --- a/eng/common/templates/job/source-build.yml +++ b/eng/common/templates/job/source-build.yml @@ -31,6 +31,12 @@ parameters: # container and pool. platform: {} + # If set to true and running on a non-public project, + # Internal blob storage locations will be enabled. + # This is not enabled by default because many repositories do not need internal sources + # and do not need to have the required service connections approved in the pipeline. + enableInternalSources: false + jobs: - job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }} displayName: Source-Build (${{ parameters.platform.name }}) @@ -61,6 +67,8 @@ jobs: clean: all steps: + - ${{ if eq(parameters.enableInternalSources, true) }}: + - template: /eng/common/templates/steps/enable-internal-runtimes.yml - template: /eng/common/templates/steps/source-build.yml parameters: platform: ${{ parameters.platform }} diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml index 43ee0c202fc..0b6bb89dc78 100644 --- a/eng/common/templates/job/source-index-stage1.yml +++ b/eng/common/templates/job/source-index-stage1.yml @@ -70,16 +70,13 @@ jobs: scriptType: 'ps' scriptLocation: 'inlineScript' inlineScript: | - echo "##vso[task.setvariable variable=ARM_CLIENT_ID]$env:servicePrincipalId" - echo "##vso[task.setvariable variable=ARM_ID_TOKEN]$env:idToken" - echo "##vso[task.setvariable variable=ARM_TENANT_ID]$env:tenantId" + echo "##vso[task.setvariable variable=ARM_CLIENT_ID;issecret=true]$env:servicePrincipalId" + echo "##vso[task.setvariable variable=ARM_ID_TOKEN;issecret=true]$env:idToken" + echo "##vso[task.setvariable variable=ARM_TENANT_ID;issecret=true]$env:tenantId" - script: | - echo "Client ID: $(ARM_CLIENT_ID)" - echo "ID Token: $(ARM_ID_TOKEN)" - echo "Tenant ID: $(ARM_TENANT_ID)" az login --service-principal -u $(ARM_CLIENT_ID) --tenant $(ARM_TENANT_ID) --allow-no-subscriptions --federated-token $(ARM_ID_TOKEN) displayName: "Login to Azure" - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) -s netsourceindexstage1 -b stage1 - displayName: Upload stage1 artifacts to source index \ No newline at end of file + displayName: Upload stage1 artifacts to source index diff --git a/eng/common/templates/jobs/source-build.yml b/eng/common/templates/jobs/source-build.yml index a15b07eb51d..5f46bfa895c 100644 --- a/eng/common/templates/jobs/source-build.yml +++ b/eng/common/templates/jobs/source-build.yml @@ -21,6 +21,12 @@ parameters: # one job runs on 'defaultManagedPlatform'. platforms: [] + # If set to true and running on a non-public project, + # Internal nuget and blob storage locations will be enabled. + # This is not enabled by default because many repositories do not need internal sources + # and do not need to have the required service connections approved in the pipeline. + enableInternalSources: false + jobs: - ${{ if ne(parameters.allCompletedJobId, '') }}: @@ -38,9 +44,11 @@ jobs: parameters: jobNamePrefix: ${{ parameters.jobNamePrefix }} platform: ${{ platform }} + enableInternalSources: ${{ parameters.enableInternalSources }} - ${{ if eq(length(parameters.platforms), 0) }}: - template: /eng/common/templates/job/source-build.yml parameters: jobNamePrefix: ${{ parameters.jobNamePrefix }} platform: ${{ parameters.defaultManagedPlatform }} + enableInternalSources: ${{ parameters.enableInternalSources }} diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index aba44a25a33..2db4933468f 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -268,14 +268,16 @@ stages: - task: NuGetAuthenticate@1 - - task: PowerShell@2 + - task: AzureCLI@2 displayName: Publish Using Darc inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 + azureSubscription: "Darc: Maestro Production" + scriptType: ps + scriptLocation: scriptPath + scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 arguments: -BuildId $(BARBuildId) -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' - -MaestroToken '$(MaestroApiAccessToken)' -WaitPublishingFinish true -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml index 0c87f149a4a..64b9abc6850 100644 --- a/eng/common/templates/post-build/setup-maestro-vars.yml +++ b/eng/common/templates/post-build/setup-maestro-vars.yml @@ -11,13 +11,14 @@ steps: artifactName: ReleaseConfigs checkDownloadedFiles: true - - task: PowerShell@2 + - task: AzureCLI@2 name: setReleaseVars displayName: Set Release Configs Vars inputs: - targetType: inline - pwsh: true - script: | + azureSubscription: "Darc: Maestro Production" + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | try { if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') { $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt @@ -31,15 +32,16 @@ steps: $AzureDevOpsBuildId = $Env:Build_BuildId } else { - $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}" + . $(Build.SourcesDirectory)\eng\common\tools.ps1 + $darc = Get-Darc + $buildInfo = & $darc get-build ` + --id ${{ parameters.BARBuildId }} ` + --extended ` + --output-format json ` + --ci ` + | convertFrom-Json - $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' - $apiHeaders.Add('Accept', 'application/json') - $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}") - - $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } - - $BarId = $Env:BARBuildId + $BarId = ${{ parameters.BARBuildId }} $Channels = $Env:PromoteToMaestroChannels -split "," $Channels = $Channels -join "][" $Channels = "[$Channels]" @@ -65,6 +67,4 @@ steps: exit 1 } env: - MAESTRO_API_TOKEN: $(MaestroApiAccessToken) - BARBuildId: ${{ parameters.BARBuildId }} PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }} diff --git a/eng/common/templates/steps/enable-internal-runtimes.yml b/eng/common/templates/steps/enable-internal-runtimes.yml new file mode 100644 index 00000000000..54dc9416c51 --- /dev/null +++ b/eng/common/templates/steps/enable-internal-runtimes.yml @@ -0,0 +1,28 @@ +# Obtains internal runtime download credentials and populates the 'dotnetbuilds-internal-container-read-token-base64' +# variable with the base64-encoded SAS token, by default + +parameters: +- name: federatedServiceConnection + type: string + default: 'dotnetbuilds-internal-read' +- name: outputVariableName + type: string + default: 'dotnetbuilds-internal-container-read-token-base64' +- name: expiryInHours + type: number + default: 1 +- name: base64Encode + type: boolean + default: true + +steps: +- ${{ if ne(variables['System.TeamProject'], 'public') }}: + - template: /eng/common/templates/steps/get-delegation-sas.yml + parameters: + federatedServiceConnection: ${{ parameters.federatedServiceConnection }} + outputVariableName: ${{ parameters.outputVariableName }} + expiryInHours: ${{ parameters.expiryInHours }} + base64Encode: ${{ parameters.base64Encode }} + storageAccount: dotnetbuilds + container: internal + permissions: rl diff --git a/eng/common/templates/steps/get-delegation-sas.yml b/eng/common/templates/steps/get-delegation-sas.yml new file mode 100644 index 00000000000..c0e8f91317f --- /dev/null +++ b/eng/common/templates/steps/get-delegation-sas.yml @@ -0,0 +1,43 @@ +parameters: +- name: federatedServiceConnection + type: string +- name: outputVariableName + type: string +- name: expiryInHours + type: number + default: 1 +- name: base64Encode + type: boolean + default: false +- name: storageAccount + type: string +- name: container + type: string +- name: permissions + type: string + default: 'rl' + +steps: +- task: AzureCLI@2 + displayName: 'Generate delegation SAS Token for ${{ parameters.storageAccount }}/${{ parameters.container }}' + inputs: + azureSubscription: ${{ parameters.federatedServiceConnection }} + scriptType: 'pscore' + scriptLocation: 'inlineScript' + inlineScript: | + # Calculate the expiration of the SAS token and convert to UTC + $expiry = (Get-Date).AddHours(${{ parameters.expiryInHours }}).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") + + $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv + + if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to generate SAS token." + exit 1 + } + + if ('${{ parameters.base64Encode }}' -eq 'true') { + $sas = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($sas)) + } + + Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value" + Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true]$sas" diff --git a/eng/common/templates/steps/get-federated-access-token.yml b/eng/common/templates/steps/get-federated-access-token.yml new file mode 100644 index 00000000000..c8c49cc0e8f --- /dev/null +++ b/eng/common/templates/steps/get-federated-access-token.yml @@ -0,0 +1,28 @@ +parameters: +- name: federatedServiceConnection + type: string +- name: outputVariableName + type: string +# Resource to get a token for. Common values include: +# - '499b84ac-1321-427f-aa17-267ca6975798' for Azure DevOps +# - 'https://storage.azure.com/' for storage +# Defaults to Azure DevOps +- name: resource + type: string + default: '499b84ac-1321-427f-aa17-267ca6975798' + +steps: +- task: AzureCLI@2 + displayName: 'Getting federated access token for feeds' + inputs: + azureSubscription: ${{ parameters.federatedServiceConnection }} + scriptType: 'pscore' + scriptLocation: 'inlineScript' + inlineScript: | + $accessToken = az account get-access-token --query accessToken --resource ${{ parameters.resource }} --output tsv + if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to get access token for resource '${{ parameters.resource }}'" + exit 1 + } + Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value" + Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true]$accessToken" \ No newline at end of file diff --git a/global.json b/global.json index fd68443e209..23f3045067d 100644 --- a/global.json +++ b/global.json @@ -13,7 +13,7 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24266.3", - "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24266.3" + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24360.5", + "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24360.5" } } From 8b6c0ded38700b2cc220131ab81677d81530054f Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Fri, 12 Jul 2024 09:25:29 -0700 Subject: [PATCH 13/32] Enable internal runtime downloads via dSAS (#34217) --- azure-pipelines.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index eb8849500db..7a3615fa6df 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,7 +18,6 @@ variables: - name: PostBuildSign value: true - group: DotNet-HelixApi-Access - - group: DotNetBuilds storage account read tokens - group: AzureDevOps-Artifact-Feeds-Pats - name: _InternalRuntimeDownloadArgs value: /p:DotNetRuntimeSourceFeed=https://dotnetbuilds.blob.core.windows.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) @@ -117,6 +116,7 @@ extends: arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token env: Token: $(dn-bot-dnceng-artifact-feeds-rw) + - template: /eng/common/templates-official/steps/enable-internal-runtimes.yml - script: eng\common\cibuild.cmd -configuration $(_BuildConfig) -prepareMachine $(_InternalBuildArgs) $(_InternalRuntimeDownloadArgs) $(_AdditionalBuildArgs) env: Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl) @@ -144,6 +144,7 @@ extends: arguments: $(Build.SourcesDirectory)/NuGet.config $Token env: Token: $(dn-bot-dnceng-artifact-feeds-rw) + - template: /eng/common/templates-official/steps/enable-internal-runtimes.yml - script: eng/common/cibuild.sh --configuration $(_BuildConfig) --prepareMachine $(_InternalRuntimeDownloadArgs) env: Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl) @@ -185,6 +186,7 @@ extends: arguments: $(Build.SourcesDirectory)/NuGet.config $Token env: Token: $(dn-bot-dnceng-artifact-feeds-rw) + - template: /eng/common/templates-official/steps/enable-internal-runtimes.yml - script: eng/common/cibuild.sh --configuration $(_BuildConfig) --prepareMachine $(_InternalRuntimeDownloadArgs) displayName: Build templateContext: @@ -224,6 +226,16 @@ extends: arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token env: Token: $(dn-bot-dnceng-artifact-feeds-rw) + - template: /eng/common/templates-official/steps/enable-internal-runtimes.yml + - template: /eng/common/templates-official/steps/get-delegation-sas.yml + parameters: + federatedServiceConnection: 'dotnetbuilds-internal-read' + outputVariableName: 'dotnetbuilds-internal-container-read-token' + expiryInHours: 1 + base64Encode: false + storageAccount: dotnetbuilds + container: internal + permissions: rl - script: restore.cmd -ci /p:configuration=$(_BuildConfig) $(_InternalRuntimeDownloadArgs) displayName: Restore packages - script: .dotnet\dotnet build eng\helix.proj /restore /t:Test /p:configuration=$(_BuildConfig) /bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog $(_InternalRuntimeDownloadArgs) From 65e7cb610848962a63829e41b89931754f8069b0 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Mon, 15 Jul 2024 14:41:54 -0700 Subject: [PATCH 14/32] Up SAS timeout to 3 hours (#34229) --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7a3615fa6df..b12ed89c253 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -231,7 +231,7 @@ extends: parameters: federatedServiceConnection: 'dotnetbuilds-internal-read' outputVariableName: 'dotnetbuilds-internal-container-read-token' - expiryInHours: 1 + expiryInHours: 3 base64Encode: false storageAccount: dotnetbuilds container: internal From 5efec9148a1d3372b4c034b966aa933a7690402f Mon Sep 17 00:00:00 2001 From: DotNet-Bot Date: Tue, 16 Jul 2024 22:58:32 +0000 Subject: [PATCH 15/32] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-runtime build 20240716.12 Microsoft.Extensions.HostFactoryResolver.Sources , Microsoft.NETCore.App.Ref , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.BrowserDebugHost.Transport From Version 8.0.7-servicing.24313.11 -> To Version 8.0.8-servicing.24366.12 --- NuGet.config | 2 ++ eng/Version.Details.xml | 16 ++++++++-------- eng/Versions.props | 8 ++++---- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/NuGet.config b/NuGet.config index bd03eeba24f..77f95a770bd 100644 --- a/NuGet.config +++ b/NuGet.config @@ -9,6 +9,7 @@ + @@ -23,6 +24,7 @@ + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 00602e05fa3..a243a361997 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -29,9 +29,9 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime 2aade6beb02ea367fd97c4070a4198802fe61c03 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 2aade6beb02ea367fd97c4070a4198802fe61c03 + 08338fcaa5c9b9a8190abb99222fed12aaba956c https://dev.azure.com/dnceng/internal/_git/dotnet-runtime @@ -41,18 +41,18 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime 2aade6beb02ea367fd97c4070a4198802fe61c03 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 2aade6beb02ea367fd97c4070a4198802fe61c03 + 08338fcaa5c9b9a8190abb99222fed12aaba956c - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 2aade6beb02ea367fd97c4070a4198802fe61c03 + 08338fcaa5c9b9a8190abb99222fed12aaba956c - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 2aade6beb02ea367fd97c4070a4198802fe61c03 + 08338fcaa5c9b9a8190abb99222fed12aaba956c diff --git a/eng/Versions.props b/eng/Versions.props index 4746f670b8d..d9054f1c116 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,12 +24,12 @@ 8.0.0 8.0.0 8.0.1 - 8.0.7-servicing.24313.11 + 8.0.8-servicing.24366.12 8.0.0 8.0.4 - 8.0.7 - 8.0.7 - 8.0.7-servicing.24313.11 + 8.0.8 + 8.0.8 + 8.0.8-servicing.24366.12 8.0.0-beta.24360.5 From e7f01650e349edfd72d02412caac582bad4b3e6d Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Wed, 17 Jul 2024 18:05:09 +0000 Subject: [PATCH 16/32] Merged PR 41160: Temporarily work around '/' in dSAS Temporarily work around '/' in dSAS When dSAS tokens contain a forward /, helix will incorrectly name the file target for a correlation payload, and then fail to unpack it. ---- #### AI description (iteration 1) #### PR Classification Bug fix to address an issue with SAS tokens containing '/' causing incorrect downloads. #### PR Summary This pull request implements a workaround for a Helix issue where SAS tokens with '/' result in incorrect downloads of correlation payloads. - `eng/common/templates/steps/get-delegation-sas.yml`: Added a loop to regenerate the SAS token if it contains a '/' character, ensuring valid tokens are generated. --- eng/common/templates/steps/get-delegation-sas.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/eng/common/templates/steps/get-delegation-sas.yml b/eng/common/templates/steps/get-delegation-sas.yml index c0e8f91317f..8fea69b6240 100644 --- a/eng/common/templates/steps/get-delegation-sas.yml +++ b/eng/common/templates/steps/get-delegation-sas.yml @@ -28,12 +28,17 @@ steps: # Calculate the expiration of the SAS token and convert to UTC $expiry = (Get-Date).AddHours(${{ parameters.expiryInHours }}).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") - $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv + # Temporarily work around a helix issue where SAS tokens with / in them will cause incorrect downloads + # of correlation payloads. + $sas = "" + do { + $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv - if ($LASTEXITCODE -ne 0) { - Write-Error "Failed to generate SAS token." - exit 1 - } + if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to generate SAS token." + exit 1 + } + } while($sas.IndexOf('/') -ne -1) if ('${{ parameters.base64Encode }}' -eq 'true') { $sas = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($sas)) From 90d079985f33ae91c05b98ecf65e0ce38270ba55 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Wed, 17 Jul 2024 20:57:14 +0000 Subject: [PATCH 17/32] Merged PR 41167: Temporarily work around '/' in dSAS Temporarily work around '/' in dSAS When dSAS tokens contain a forward /, helix will incorrectly name the file target for a correlation payload, and then fail to unpack it. ---- #### AI description (iteration 1) #### PR Classification Bug fix to address an issue with SAS tokens containing '/' causing incorrect downloads. #### PR Summary This pull request implements a workaround for a Helix issue where SAS tokens with '/' result in incorrect downloads of correlation payloads. - `eng/common/templates-official/steps/get-delegation-sas.yml`: Added a loop to regenerate SAS tokens until one without '/' is obtained. --- .../steps/get-delegation-sas.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/eng/common/templates-official/steps/get-delegation-sas.yml b/eng/common/templates-official/steps/get-delegation-sas.yml index c0e8f91317f..8fea69b6240 100644 --- a/eng/common/templates-official/steps/get-delegation-sas.yml +++ b/eng/common/templates-official/steps/get-delegation-sas.yml @@ -28,12 +28,17 @@ steps: # Calculate the expiration of the SAS token and convert to UTC $expiry = (Get-Date).AddHours(${{ parameters.expiryInHours }}).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") - $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv + # Temporarily work around a helix issue where SAS tokens with / in them will cause incorrect downloads + # of correlation payloads. + $sas = "" + do { + $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv - if ($LASTEXITCODE -ne 0) { - Write-Error "Failed to generate SAS token." - exit 1 - } + if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to generate SAS token." + exit 1 + } + } while($sas.IndexOf('/') -ne -1) if ('${{ parameters.base64Encode }}' -eq 'true') { $sas = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($sas)) From 43302cd22fad76f357476433c1d5158777d6b4cd Mon Sep 17 00:00:00 2001 From: Sean Reeser Date: Tue, 6 Aug 2024 11:20:35 -0700 Subject: [PATCH 18/32] Update branding to 8.0.9 --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index 4746f670b8d..48d03ba8a2a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,6 +1,6 @@ - 8.0.8 + 8.0.9 servicing From 114195bc8c8d15315bb8607bb773b872923dadc7 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Tue, 6 Aug 2024 13:42:17 -0700 Subject: [PATCH 19/32] [release/8.0] Update Helix pools (#34232) --- azure-pipelines-public.yml | 4 ++-- azure-pipelines.yml | 2 +- eng/helix.proj | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines-public.yml b/azure-pipelines-public.yml index f4436166dc3..b9d5a94f76a 100644 --- a/azure-pipelines-public.yml +++ b/azure-pipelines-public.yml @@ -269,12 +269,12 @@ stages: value: $(_BuildConfig) - ${{ if eq(variables['System.TeamProject'], 'public') }}: - name: HelixTargetQueues - value: OSX.1100.Amd64.Open;(Ubuntu.2004.Amd64.SqlServer)Ubuntu.2004.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-sqlserver-amd64 + value: Windows.10.Amd64.Open;OSX.1200.Amd64.Open;Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-sqlserver-amd64 - name: _HelixAccessToken value: '' # Needed for public queues - ${{ if ne(variables['System.TeamProject'], 'public') }}: - name: HelixTargetQueues - value: OSX.1100.Amd64;(Ubuntu.2004.Amd64.SqlServer)Ubuntu.2004.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-sqlserver-amd64 + value: Windows.10.Amd64;OSX.1200.Amd64;Ubuntu.2204.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-sqlserver-amd64 - name: _HelixAccessToken value: $(HelixApiAccessToken) # Needed for internal queues steps: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b12ed89c253..d4d93048f1b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -208,7 +208,7 @@ extends: - name: _HelixBuildConfig value: $(_BuildConfig) - name: HelixTargetQueues - value: OSX.1100.Amd64;(Ubuntu.2004.Amd64.SqlServer)Ubuntu.2004.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-sqlserver-amd64 + value: Windows.10.Amd64;OSX.1200.Amd64;Ubuntu.2204.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-sqlserver-amd64 - name: _HelixAccessToken # Needed for internal queues value: $(HelixApiAccessToken) diff --git a/eng/helix.proj b/eng/helix.proj index c0f654f9467..a25f22b711d 100644 --- a/eng/helix.proj +++ b/eng/helix.proj @@ -17,7 +17,7 @@ - Windows.10.Amd64.Open;OSX.1200.Amd64.Open;Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-sqlserver-amd64 + Windows.10.Amd64.Open;OSX.1200.Amd64.Open;Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-sqlserver-amd64 false efcore/localbuild/ t001 From 7686ab5ad87ca65515fc5e7b6e70f17c6b3eef6e Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Tue, 6 Aug 2024 13:43:23 -0700 Subject: [PATCH 20/32] [release/8.0] Use placeholder value to fix CredScan (#34342) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can use the special value `PLACEHOLDER` to tell CredScan these credentials are fake ones. Co-authored-by: Alexander Köplinger --- azure-pipelines-public.yml | 2 +- azure-pipelines.yml | 2 +- eng/helix.proj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines-public.yml b/azure-pipelines-public.yml index b9d5a94f76a..f7421f55839 100644 --- a/azure-pipelines-public.yml +++ b/azure-pipelines-public.yml @@ -299,7 +299,7 @@ stages: env: HelixAccessToken: $(_HelixAccessToken) SYSTEM_ACCESSTOKEN: $(System.AccessToken) # We need to set this env var to publish helix results to Azure Dev Ops - MSSQL_SA_PASSWORD: "Password12!" + MSSQL_SA_PASSWORD: "PLACEHOLDER" COMPlus_EnableWriteXorExecute: 0 # Work-around for https://github.com/dotnet/runtime/issues/70758 DotNetBuildsInternalReadSasToken: $(dotnetbuilds-internal-container-read-token) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d4d93048f1b..6629d18b98f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -244,7 +244,7 @@ extends: HelixAccessToken: $(_HelixAccessToken) # We need to set this env var to publish helix results to Azure Dev Ops SYSTEM_ACCESSTOKEN: $(System.AccessToken) - MSSQL_SA_PASSWORD: "Password12!" + MSSQL_SA_PASSWORD: "PLACEHOLDER" # Work-around for https://github.com/dotnet/runtime/issues/70758 COMPlus_EnableWriteXorExecute: 0 DotNetBuildsInternalReadSasToken: $(dotnetbuilds-internal-container-read-token) diff --git a/eng/helix.proj b/eng/helix.proj index a25f22b711d..acec0077401 100644 --- a/eng/helix.proj +++ b/eng/helix.proj @@ -21,7 +21,7 @@ false efcore/localbuild/ t001 - Password12! + PLACEHOLDER From 9f3091b9d8153c3672e1a890730ec72b2688eabb Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Sat, 10 Aug 2024 03:26:10 -0700 Subject: [PATCH 21/32] [release/8.0] Find the discriminator property even if it is not string (#34388) Fixes #34201 --- src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs | 4 ++++ .../Migrations/Internal/MigrationsModelDifferTest.cs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs b/src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs index b9ab85070bb..24333f89885 100644 --- a/src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs @@ -15,6 +15,9 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Internal; public abstract class InternalTypeBaseBuilder : AnnotatableBuilder, IConventionTypeBaseBuilder { + private static readonly bool UseOldBehavior34201 = + AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue34201", out var enabled34201) && enabled34201; + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -204,6 +207,7 @@ public static bool IsCompatible(MemberInfo? newMemberInfo, PropertyBase existing || (memberInfo is PropertyInfo propertyInfo && propertyInfo.IsIndexerProperty())) { if (existingProperty.GetTypeConfigurationSource() is ConfigurationSource existingTypeConfigurationSource + && (typeConfigurationSource != null || UseOldBehavior34201) && !typeConfigurationSource.Overrides(existingTypeConfigurationSource)) { return null; diff --git a/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs b/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs index b0f732c5b56..aa91709aaec 100644 --- a/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs +++ b/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs @@ -8646,7 +8646,7 @@ public void Split_out_subtype_with_seed_data() x.Property("Name"); x.Property("Discriminator"); - x.HasDiscriminator("Discriminator") + x.HasDiscriminator() .HasValue(1) .HasValue(2); From ef52f58f36c6dfaa00e1bad887e042d9906b68f5 Mon Sep 17 00:00:00 2001 From: vseanreesermsft <78103370+vseanreesermsft@users.noreply.github.com> Date: Thu, 29 Aug 2024 12:05:03 -0700 Subject: [PATCH 22/32] Update branding to 8.0.10 (#34571) --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index 6efb74f8169..18a59a8f03f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,6 +1,6 @@ - 8.0.9 + 8.0.10 servicing From c0fee2fcc1da80d2c5235d470024efa77427df9c Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Fri, 30 Aug 2024 16:11:16 -0700 Subject: [PATCH 23/32] [release/9.0] Always include generated files in the compilation (#34547) Fixes #34546 --- ...Microsoft.EntityFrameworkCore.Tasks.targets | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/EFCore.Tasks/buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets b/src/EFCore.Tasks/buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets index 507ea1d8165..25463696b4c 100644 --- a/src/EFCore.Tasks/buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets +++ b/src/EFCore.Tasks/buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets @@ -114,15 +114,14 @@ For Publish: - - - + + + Condition="Exists('$(EFGeneratedSourcesBuildFile)')"> + Condition="Exists('$(EFGeneratedSourcesPublishFile)')"> @@ -185,12 +184,15 @@ For Publish: @(_DebugSymbolsIntermediatePath); $(NonExistentFile); @(CustomAdditionalCompileOutputs)"> + + + + + + - - - From e49bbfbb49f98587b8bf26356b89157fb81d3807 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 31 Aug 2024 03:04:31 +0000 Subject: [PATCH 24/32] Update dependencies from https://github.com/dotnet/arcade build 20240826.2 (#34583) [release/8.0] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 2 +- eng/common/sdl/NuGet.config | 4 ++-- eng/common/sdl/execute-all-sdl-tools.ps1 | 4 +--- eng/common/sdl/init-sdl.ps1 | 8 -------- eng/common/sdl/sdl.ps1 | 4 +++- .../job/publish-build-assets.yml | 2 +- .../templates-official/post-build/post-build.yml | 2 +- .../templates-official/steps/execute-sdl.yml | 2 -- .../steps/get-delegation-sas.yml | 15 +++++---------- .../steps/get-federated-access-token.yml | 14 +++++++++++++- eng/common/templates/job/publish-build-assets.yml | 2 +- eng/common/templates/post-build/post-build.yml | 2 +- eng/common/templates/steps/execute-sdl.yml | 7 ++++--- eng/common/templates/steps/get-delegation-sas.yml | 15 +++++---------- .../steps/get-federated-access-token.yml | 14 +++++++++++++- eng/common/templates/steps/telemetry-start.yml | 2 +- global.json | 8 ++++---- 18 files changed, 62 insertions(+), 57 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a243a361997..7bc188e91f9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -56,17 +56,17 @@ - + https://github.com/dotnet/arcade - c9efa535175049eb9cba06cae1f8c3d5dbe768a9 + 80264e60280e2815e7d65871081ccac04a32445c - + https://github.com/dotnet/arcade - c9efa535175049eb9cba06cae1f8c3d5dbe768a9 + 80264e60280e2815e7d65871081ccac04a32445c - + https://github.com/dotnet/arcade - c9efa535175049eb9cba06cae1f8c3d5dbe768a9 + 80264e60280e2815e7d65871081ccac04a32445c diff --git a/eng/Versions.props b/eng/Versions.props index 18a59a8f03f..271e3e739a2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -32,7 +32,7 @@ 8.0.8-servicing.24366.12 - 8.0.0-beta.24360.5 + 8.0.0-beta.24426.2 diff --git a/eng/common/sdl/NuGet.config b/eng/common/sdl/NuGet.config index 3849bdb3cf5..5bfbb02ef04 100644 --- a/eng/common/sdl/NuGet.config +++ b/eng/common/sdl/NuGet.config @@ -5,11 +5,11 @@ - + - + diff --git a/eng/common/sdl/execute-all-sdl-tools.ps1 b/eng/common/sdl/execute-all-sdl-tools.ps1 index 4715d75e974..81ded5b7f47 100644 --- a/eng/common/sdl/execute-all-sdl-tools.ps1 +++ b/eng/common/sdl/execute-all-sdl-tools.ps1 @@ -6,7 +6,6 @@ Param( [string] $BranchName=$env:BUILD_SOURCEBRANCH, # Optional: name of branch or version of gdn settings; defaults to master [string] $SourceDirectory=$env:BUILD_SOURCESDIRECTORY, # Required: the directory where source files are located [string] $ArtifactsDirectory = (Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY ('artifacts')), # Required: the directory where build artifacts are located - [string] $AzureDevOpsAccessToken, # Required: access token for dnceng; should be provided via KeyVault # Optional: list of SDL tools to run on source code. See 'configure-sdl-tool.ps1' for tools list # format. @@ -75,7 +74,7 @@ try { } Exec-BlockVerbosely { - & $(Join-Path $PSScriptRoot 'init-sdl.ps1') -GuardianCliLocation $guardianCliLocation -Repository $RepoName -BranchName $BranchName -WorkingDirectory $workingDirectory -AzureDevOpsAccessToken $AzureDevOpsAccessToken -GuardianLoggerLevel $GuardianLoggerLevel + & $(Join-Path $PSScriptRoot 'init-sdl.ps1') -GuardianCliLocation $guardianCliLocation -Repository $RepoName -BranchName $BranchName -WorkingDirectory $workingDirectory -GuardianLoggerLevel $GuardianLoggerLevel } $gdnFolder = Join-Path $workingDirectory '.gdn' @@ -104,7 +103,6 @@ try { -TargetDirectory $targetDirectory ` -GdnFolder $gdnFolder ` -ToolsList $tools ` - -AzureDevOpsAccessToken $AzureDevOpsAccessToken ` -GuardianLoggerLevel $GuardianLoggerLevel ` -CrScanAdditionalRunConfigParams $CrScanAdditionalRunConfigParams ` -PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams ` diff --git a/eng/common/sdl/init-sdl.ps1 b/eng/common/sdl/init-sdl.ps1 index 3ac1d92b370..588ff8e22fb 100644 --- a/eng/common/sdl/init-sdl.ps1 +++ b/eng/common/sdl/init-sdl.ps1 @@ -3,7 +3,6 @@ Param( [string] $Repository, [string] $BranchName='master', [string] $WorkingDirectory, - [string] $AzureDevOpsAccessToken, [string] $GuardianLoggerLevel='Standard' ) @@ -21,14 +20,7 @@ $ci = $true # Don't display the console progress UI - it's a huge perf hit $ProgressPreference = 'SilentlyContinue' -# Construct basic auth from AzDO access token; construct URI to the repository's gdn folder stored in that repository; construct location of zip file -$encodedPat = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$AzureDevOpsAccessToken")) -$escapedRepository = [Uri]::EscapeDataString("/$Repository/$BranchName/.gdn") -$uri = "https://dev.azure.com/dnceng/internal/_apis/git/repositories/sdl-tool-cfg/Items?path=$escapedRepository&versionDescriptor[versionOptions]=0&`$format=zip&api-version=5.0" -$zipFile = "$WorkingDirectory/gdn.zip" - Add-Type -AssemblyName System.IO.Compression.FileSystem -$gdnFolder = (Join-Path $WorkingDirectory '.gdn') try { # if the folder does not exist, we'll do a guardian init and push it to the remote repository diff --git a/eng/common/sdl/sdl.ps1 b/eng/common/sdl/sdl.ps1 index 648c5068d7d..7fe603fe995 100644 --- a/eng/common/sdl/sdl.ps1 +++ b/eng/common/sdl/sdl.ps1 @@ -4,6 +4,8 @@ function Install-Gdn { [Parameter(Mandatory=$true)] [string]$Path, + [string]$Source = "https://pkgs.dev.azure.com/dnceng/_packaging/Guardian1ESPTUpstreamOrgFeed/nuget/v3/index.json", + # If omitted, install the latest version of Guardian, otherwise install that specific version. [string]$Version ) @@ -19,7 +21,7 @@ function Install-Gdn { $ci = $true . $PSScriptRoot\..\tools.ps1 - $argumentList = @("install", "Microsoft.Guardian.Cli", "-Source https://securitytools.pkgs.visualstudio.com/_packaging/Guardian/nuget/v3/index.json", "-OutputDirectory $Path", "-NonInteractive", "-NoCache") + $argumentList = @("install", "Microsoft.Guardian.Cli.win-x64", "-Source $Source", "-OutputDirectory $Path", "-NonInteractive", "-NoCache") if ($Version) { $argumentList += "-Version $Version" diff --git a/eng/common/templates-official/job/publish-build-assets.yml b/eng/common/templates-official/job/publish-build-assets.yml index ba3e7df8158..0117328800c 100644 --- a/eng/common/templates-official/job/publish-build-assets.yml +++ b/eng/common/templates-official/job/publish-build-assets.yml @@ -149,7 +149,7 @@ jobs: scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 arguments: -BuildId $(BARBuildId) -PublishingInfraVersion 3 - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' + -AzdoToken '$(System.AccessToken)' -WaitPublishingFinish true -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/templates-official/post-build/post-build.yml b/eng/common/templates-official/post-build/post-build.yml index 0dfa387e7b7..b81b8770b34 100644 --- a/eng/common/templates-official/post-build/post-build.yml +++ b/eng/common/templates-official/post-build/post-build.yml @@ -281,7 +281,7 @@ stages: scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 arguments: -BuildId $(BARBuildId) -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' + -AzdoToken '$(System.AccessToken)' -WaitPublishingFinish true -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/templates-official/steps/execute-sdl.yml b/eng/common/templates-official/steps/execute-sdl.yml index 07426fde05d..301d5c591eb 100644 --- a/eng/common/templates-official/steps/execute-sdl.yml +++ b/eng/common/templates-official/steps/execute-sdl.yml @@ -9,8 +9,6 @@ parameters: steps: - task: NuGetAuthenticate@1 - inputs: - nuGetServiceConnections: GuardianConnect - task: NuGetToolInstaller@1 displayName: 'Install NuGet.exe' diff --git a/eng/common/templates-official/steps/get-delegation-sas.yml b/eng/common/templates-official/steps/get-delegation-sas.yml index 8fea69b6240..c0e8f91317f 100644 --- a/eng/common/templates-official/steps/get-delegation-sas.yml +++ b/eng/common/templates-official/steps/get-delegation-sas.yml @@ -28,17 +28,12 @@ steps: # Calculate the expiration of the SAS token and convert to UTC $expiry = (Get-Date).AddHours(${{ parameters.expiryInHours }}).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") - # Temporarily work around a helix issue where SAS tokens with / in them will cause incorrect downloads - # of correlation payloads. - $sas = "" - do { - $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv + $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv - if ($LASTEXITCODE -ne 0) { - Write-Error "Failed to generate SAS token." - exit 1 - } - } while($sas.IndexOf('/') -ne -1) + if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to generate SAS token." + exit 1 + } if ('${{ parameters.base64Encode }}' -eq 'true') { $sas = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($sas)) diff --git a/eng/common/templates-official/steps/get-federated-access-token.yml b/eng/common/templates-official/steps/get-federated-access-token.yml index e3786cef6df..55e33bd38f7 100644 --- a/eng/common/templates-official/steps/get-federated-access-token.yml +++ b/eng/common/templates-official/steps/get-federated-access-token.yml @@ -3,6 +3,12 @@ parameters: type: string - name: outputVariableName type: string +- name: stepName + type: string + default: 'getFederatedAccessToken' +- name: condition + type: string + default: '' # Resource to get a token for. Common values include: # - '499b84ac-1321-427f-aa17-267ca6975798' for Azure DevOps # - 'https://storage.azure.com/' for storage @@ -10,10 +16,16 @@ parameters: - name: resource type: string default: '499b84ac-1321-427f-aa17-267ca6975798' +- name: isStepOutputVariable + type: boolean + default: false steps: - task: AzureCLI@2 displayName: 'Getting federated access token for feeds' + name: ${{ parameters.stepName }} + ${{ if ne(parameters.condition, '') }}: + condition: ${{ parameters.condition }} inputs: azureSubscription: ${{ parameters.federatedServiceConnection }} scriptType: 'pscore' @@ -25,4 +37,4 @@ steps: exit 1 } Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value" - Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true]$accessToken" + Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true;isOutput=${{ parameters.isStepOutputVariable }}]$accessToken" \ No newline at end of file diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml index 57a41f0a3e1..cc2b346ba8b 100644 --- a/eng/common/templates/job/publish-build-assets.yml +++ b/eng/common/templates/job/publish-build-assets.yml @@ -145,7 +145,7 @@ jobs: scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 arguments: -BuildId $(BARBuildId) -PublishingInfraVersion 3 - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' + -AzdoToken '$(System.AccessToken)' -WaitPublishingFinish true -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index 2db4933468f..c3b6a3012fe 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -277,7 +277,7 @@ stages: scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 arguments: -BuildId $(BARBuildId) -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' + -AzdoToken '$(System.AccessToken)' -WaitPublishingFinish true -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/templates/steps/execute-sdl.yml b/eng/common/templates/steps/execute-sdl.yml index 07426fde05d..fe0ebf8c904 100644 --- a/eng/common/templates/steps/execute-sdl.yml +++ b/eng/common/templates/steps/execute-sdl.yml @@ -9,8 +9,6 @@ parameters: steps: - task: NuGetAuthenticate@1 - inputs: - nuGetServiceConnections: GuardianConnect - task: NuGetToolInstaller@1 displayName: 'Install NuGet.exe' @@ -36,16 +34,19 @@ steps: displayName: Execute SDL (Overridden) continueOnError: ${{ parameters.sdlContinueOnError }} condition: ${{ parameters.condition }} + env: + GUARDIAN_DEFAULT_PACKAGE_SOURCE_SECRET: $(System.AccessToken) - ${{ if eq(parameters.overrideParameters, '') }}: - powershell: ${{ parameters.executeAllSdlToolsScript }} -GuardianCliLocation $(GuardianCliLocation) -NugetPackageDirectory $(Build.SourcesDirectory)\.packages - -AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw) ${{ parameters.additionalParameters }} displayName: Execute SDL continueOnError: ${{ parameters.sdlContinueOnError }} condition: ${{ parameters.condition }} + env: + GUARDIAN_DEFAULT_PACKAGE_SOURCE_SECRET: $(System.AccessToken) - ${{ if ne(parameters.publishGuardianDirectoryToPipeline, 'false') }}: # We want to publish the Guardian results and configuration for easy diagnosis. However, the diff --git a/eng/common/templates/steps/get-delegation-sas.yml b/eng/common/templates/steps/get-delegation-sas.yml index 8fea69b6240..c0e8f91317f 100644 --- a/eng/common/templates/steps/get-delegation-sas.yml +++ b/eng/common/templates/steps/get-delegation-sas.yml @@ -28,17 +28,12 @@ steps: # Calculate the expiration of the SAS token and convert to UTC $expiry = (Get-Date).AddHours(${{ parameters.expiryInHours }}).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") - # Temporarily work around a helix issue where SAS tokens with / in them will cause incorrect downloads - # of correlation payloads. - $sas = "" - do { - $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv + $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv - if ($LASTEXITCODE -ne 0) { - Write-Error "Failed to generate SAS token." - exit 1 - } - } while($sas.IndexOf('/') -ne -1) + if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to generate SAS token." + exit 1 + } if ('${{ parameters.base64Encode }}' -eq 'true') { $sas = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($sas)) diff --git a/eng/common/templates/steps/get-federated-access-token.yml b/eng/common/templates/steps/get-federated-access-token.yml index c8c49cc0e8f..55e33bd38f7 100644 --- a/eng/common/templates/steps/get-federated-access-token.yml +++ b/eng/common/templates/steps/get-federated-access-token.yml @@ -3,6 +3,12 @@ parameters: type: string - name: outputVariableName type: string +- name: stepName + type: string + default: 'getFederatedAccessToken' +- name: condition + type: string + default: '' # Resource to get a token for. Common values include: # - '499b84ac-1321-427f-aa17-267ca6975798' for Azure DevOps # - 'https://storage.azure.com/' for storage @@ -10,10 +16,16 @@ parameters: - name: resource type: string default: '499b84ac-1321-427f-aa17-267ca6975798' +- name: isStepOutputVariable + type: boolean + default: false steps: - task: AzureCLI@2 displayName: 'Getting federated access token for feeds' + name: ${{ parameters.stepName }} + ${{ if ne(parameters.condition, '') }}: + condition: ${{ parameters.condition }} inputs: azureSubscription: ${{ parameters.federatedServiceConnection }} scriptType: 'pscore' @@ -25,4 +37,4 @@ steps: exit 1 } Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value" - Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true]$accessToken" \ No newline at end of file + Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true;isOutput=${{ parameters.isStepOutputVariable }}]$accessToken" \ No newline at end of file diff --git a/eng/common/templates/steps/telemetry-start.yml b/eng/common/templates/steps/telemetry-start.yml index 32c01ef0b55..6abbcb33a67 100644 --- a/eng/common/templates/steps/telemetry-start.yml +++ b/eng/common/templates/steps/telemetry-start.yml @@ -8,7 +8,7 @@ parameters: steps: - ${{ if and(eq(parameters.runAsPublic, 'false'), not(eq(variables['System.TeamProject'], 'public'))) }}: - - task: AzureKeyVault@1 + - task: AzureKeyVault@2 inputs: azureSubscription: 'HelixProd_KeyVault' KeyVaultName: HelixProdKV diff --git a/global.json b/global.json index 23f3045067d..528c6ba8045 100644 --- a/global.json +++ b/global.json @@ -1,11 +1,11 @@ { "sdk": { - "version": "8.0.101", + "version": "8.0.108", "allowPrerelease": true, "rollForward": "latestMajor" }, "tools": { - "dotnet": "8.0.101", + "dotnet": "8.0.108", "runtimes": { "dotnet": [ "$(MicrosoftNETCoreBrowserDebugHostTransportVersion)" @@ -13,7 +13,7 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24360.5", - "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24360.5" + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24426.2", + "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24426.2" } } From c7d5045abde403f08513a5b1e543a1e8f9ff9a68 Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Sat, 31 Aug 2024 07:53:52 +0100 Subject: [PATCH 25/32] Map directly to JSON id for types converted to string (#34564) (#34577) Fixes #34554 I also needed to fix #34511 to make this work. This was happening because we were removing the by-convention property added by property discovery. We only need to remove it when it's the computed property as well, which is handled by the other case. --- .../Conventions/CosmosJsonIdConvention.cs | 20 +- .../EndToEndCosmosTest.cs | 4 +- .../CosmosModelBuilderGenericTest.cs | 180 ++++++++++++++++++ ...mPartitionKeyQueryDiscriminatorInIdTest.cs | 64 ++++--- .../ReadItemPartitionKeyQueryFixtureBase.cs | 20 +- ...PartitionKeyQueryInheritanceFixtureBase.cs | 16 +- ...temPartitionKeyQueryInheritanceTestBase.cs | 52 +++-- ...artitionKeyQueryNoDiscriminatorInIdTest.cs | 62 +++--- ...titionKeyQueryRootDiscriminatorInIdTest.cs | 60 +++--- .../Query/ReadItemPartitionKeyQueryTest.cs | 31 ++- .../ReadItemPartitionKeyQueryTestBase.cs | 53 ++++-- 11 files changed, 390 insertions(+), 172 deletions(-) diff --git a/src/EFCore.Cosmos/Metadata/Conventions/CosmosJsonIdConvention.cs b/src/EFCore.Cosmos/Metadata/Conventions/CosmosJsonIdConvention.cs index 0340619574b..130041d556d 100644 --- a/src/EFCore.Cosmos/Metadata/Conventions/CosmosJsonIdConvention.cs +++ b/src/EFCore.Cosmos/Metadata/Conventions/CosmosJsonIdConvention.cs @@ -84,17 +84,16 @@ private void ProcessEntityType(IConventionEntityType entityType, IConventionCont { // If the entity type is not a keyed, root document in the container, then it doesn't have an `id` mapping, so // undo anything that was done by previous execution of this convention. - if (jsonIdProperty != null) + if (jsonIdProperty is not null) { jsonIdProperty.Builder.ToJsonProperty(null); - entityType.Builder.HasNoProperty(jsonIdProperty); + entityType.Builder.RemoveUnusedImplicitProperties([jsonIdProperty]); } - if (computedIdProperty != null + if (computedIdProperty is not null && computedIdProperty != jsonIdProperty) { - entityType.Builder.HasNoProperty(computedIdProperty); - } + entityType.Builder.RemoveUnusedImplicitProperties([computedIdProperty]); } return; } @@ -115,10 +114,17 @@ private void ProcessEntityType(IConventionEntityType entityType, IConventionCont // - IDiscriminatorPropertySetConvention // - IEntityTypeBaseTypeChangedConvention var idDefinition = DefinitionFactory.Create((IEntityType)entityType)!; - var keyProperty = (IConventionProperty?)idDefinition.Properties.FirstOrDefault(); if (idDefinition is { IncludesDiscriminator: false, Properties.Count: 1 }) { - var clrType = keyProperty!.GetValueConverter()?.ProviderClrType ?? keyProperty.ClrType; + // If the property maps to a string in the JSON document, then we can use it directly, even if a value converter + // is applied. On the other hand, if it maps to a numeric or bool, then we need to duplicate this to preserve the + // non-string value for queries. + var keyProperty = (IConventionProperty)idDefinition.Properties.First(); + var mapping = Dependencies.TypeMappingSource.FindMapping((IProperty)keyProperty); + var clrType = mapping?.Converter?.ProviderClrType + ?? mapping?.ClrType + ?? keyProperty!.ClrType; + if (clrType == typeof(string)) { // We are at the point where we are going to map the `id` directly to the PK. diff --git a/test/EFCore.Cosmos.FunctionalTests/EndToEndCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/EndToEndCosmosTest.cs index 4c08c77bc07..c4691b71fca 100644 --- a/test/EFCore.Cosmos.FunctionalTests/EndToEndCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/EndToEndCosmosTest.cs @@ -700,12 +700,12 @@ public async Task Entities_with_null_PK_can_be_added_with_normal_use_of_DbContex var entry = await context.AddAsync(item); - var id = entry.Property("__id").CurrentValue; + var id = entry.Property("Id").CurrentValue; Assert.NotNull(item.Id); Assert.NotNull(id); - Assert.Equal($"{item.Id}", id); + Assert.Equal(item.Id, id); Assert.Equal(EntityState.Added, entry.State); } diff --git a/test/EFCore.Cosmos.FunctionalTests/ModelBuilding/CosmosModelBuilderGenericTest.cs b/test/EFCore.Cosmos.FunctionalTests/ModelBuilding/CosmosModelBuilderGenericTest.cs index 9f8bb60182c..4d8994ef478 100644 --- a/test/EFCore.Cosmos.FunctionalTests/ModelBuilding/CosmosModelBuilderGenericTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/ModelBuilding/CosmosModelBuilderGenericTest.cs @@ -537,6 +537,186 @@ public virtual void No_alternate_key_is_created_if_id_is_hierarchical_partition_ Assert.DoesNotContain(entity.GetKeys(), k => k != entity.FindPrimaryKey()); } + [ConditionalFact] + public virtual void Single_string_primary_key_maps_to_JSON_id() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity(); + + var model = modelBuilder.FinalizeModel(); + + var entityType = model.FindEntityType(typeof(SingleStringKey))!; + + Assert.Equal( + [nameof(SingleStringKey.Id)], + entityType.FindPrimaryKey()!.Properties.Select(p => p.Name)); + + Assert.Equal( + [ + nameof(SingleStringKey.Id), "$type", nameof(SingleStringKey.Name), nameof(SingleStringKey.P1), + nameof(SingleStringKey.P2), nameof(SingleStringKey.P3), "__jObject" + ], + entityType.GetProperties().Select(p => p.Name)); + + Assert.Equal(1, entityType.GetKeys().Count()); + Assert.Null(entityType.FindProperty("__id")); + Assert.Equal("id", entityType.FindProperty("Id")!.GetJsonPropertyName()); + } + + [ConditionalFact] // Issue #34511 + public virtual void Single_string_primary_key_with_single_partition_key_maps_to_JSON_id() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity().HasPartitionKey(e => e.P1); + + var model = modelBuilder.FinalizeModel(); + + var entityType = model.FindEntityType(typeof(SingleStringKey))!; + + Assert.Equal( + [nameof(SingleStringKey.Id), nameof(SingleStringKey.P1)], + entityType.FindPrimaryKey()!.Properties.Select(p => p.Name)); + + Assert.Equal( + [ + nameof(SingleStringKey.Id), nameof(SingleStringKey.P1), "$type", nameof(SingleStringKey.Name), + nameof(SingleStringKey.P2), nameof(SingleStringKey.P3), "__jObject" + ], + entityType.GetProperties().Select(p => p.Name)); + + Assert.Equal(1, entityType.GetKeys().Count()); + Assert.Null(entityType.FindProperty("__id")); + Assert.Equal("id", entityType.FindProperty("Id")!.GetJsonPropertyName()); + } + + [ConditionalFact] // Issue #34511 + public virtual void Single_string_primary_key_with_hierarchical_partition_key_maps_to_JSON_id() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity().HasPartitionKey(e => new { e.P1, e.P2, e.P3 }); + + var model = modelBuilder.FinalizeModel(); + + var entityType = model.FindEntityType(typeof(SingleStringKey))!; + + Assert.Equal( + [nameof(SingleStringKey.Id), nameof(SingleStringKey.P1), nameof(SingleStringKey.P2), nameof(SingleStringKey.P3)], + entityType.FindPrimaryKey()!.Properties.Select(p => p.Name)); + + Assert.Equal( + [ + nameof(SingleStringKey.Id), nameof(SingleStringKey.P1), nameof(SingleStringKey.P2), nameof(SingleStringKey.P3), + "$type", nameof(SingleStringKey.Name), "__jObject" + ], + entityType.GetProperties().Select(p => p.Name)); + + Assert.Equal(1, entityType.GetKeys().Count()); + Assert.Null(entityType.FindProperty("__id")); + Assert.Equal("id", entityType.FindProperty("Id")!.GetJsonPropertyName()); + } + + protected class SingleStringKey + { + public string Id { get; set; } = null!; + public string? Name { get; set; } + public string P1 { get; set; } = null!; + public string P2 { get; set; } = null!; + public string P3 { get; set; } = null!; + } + + [ConditionalFact] // Issue #34554 + public virtual void Single_GUID_primary_key_maps_to_JSON_id() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity(); + + var model = modelBuilder.FinalizeModel(); + + var entityType = model.FindEntityType(typeof(SingleGuidKey))!; + + Assert.Equal( + [nameof(SingleGuidKey.Id)], + entityType.FindPrimaryKey()!.Properties.Select(p => p.Name)); + + Assert.Equal( + [ + nameof(SingleGuidKey.Id), "$type", nameof(SingleGuidKey.Name), nameof(SingleGuidKey.P1), + nameof(SingleGuidKey.P2), nameof(SingleGuidKey.P3), "__jObject" + ], + entityType.GetProperties().Select(p => p.Name)); + + Assert.Equal(1, entityType.GetKeys().Count()); + Assert.Null(entityType.FindProperty("__id")); + Assert.Equal("id", entityType.FindProperty("Id")!.GetJsonPropertyName()); + } + + [ConditionalFact] // Issue #34554 + public virtual void Single_GUID_primary_key_with_single_partition_key_maps_to_JSON_id() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity().HasPartitionKey(e => e.P1); + + var model = modelBuilder.FinalizeModel(); + + var entityType = model.FindEntityType(typeof(SingleGuidKey))!; + + Assert.Equal( + [nameof(SingleGuidKey.Id), nameof(SingleGuidKey.P1)], + entityType.FindPrimaryKey()!.Properties.Select(p => p.Name)); + + Assert.Equal( + [ + nameof(SingleGuidKey.Id), nameof(SingleGuidKey.P1), "$type", nameof(SingleGuidKey.Name), + nameof(SingleGuidKey.P2), nameof(SingleGuidKey.P3), "__jObject" + ], + entityType.GetProperties().Select(p => p.Name)); + + Assert.Equal(1, entityType.GetKeys().Count()); + Assert.Null(entityType.FindProperty("__id")); + Assert.Equal("id", entityType.FindProperty("Id")!.GetJsonPropertyName()); + } + + [ConditionalFact] // Issue #34554 + public virtual void Single_GUID_primary_key_with_hierarchical_partition_key_maps_to_JSON_id() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity().HasPartitionKey(e => new { e.P1, e.P2, e.P3 }); + + var model = modelBuilder.FinalizeModel(); + + var entityType = model.FindEntityType(typeof(SingleGuidKey))!; + + Assert.Equal( + [nameof(SingleGuidKey.Id), nameof(SingleGuidKey.P1), nameof(SingleGuidKey.P2), nameof(SingleGuidKey.P3)], + entityType.FindPrimaryKey()!.Properties.Select(p => p.Name)); + + Assert.Equal( + [ + nameof(SingleGuidKey.Id), nameof(SingleGuidKey.P1), nameof(SingleGuidKey.P2), nameof(SingleGuidKey.P3), + "$type", nameof(SingleGuidKey.Name), "__jObject" + ], + entityType.GetProperties().Select(p => p.Name)); + + Assert.Equal(1, entityType.GetKeys().Count()); + Assert.Null(entityType.FindProperty("__id")); + Assert.Equal("id", entityType.FindProperty("Id")!.GetJsonPropertyName()); + } + + protected class SingleGuidKey + { + public Guid Id { get; set; } + public string? Name { get; set; } + public string P1 { get; set; } = null!; + public string P2 { get; set; } = null!; + public string P3 { get; set; } = null!; + } + protected override TestModelBuilder CreateModelBuilder(Action? configure = null) => new GenericTestModelBuilder(Fixture, configure); } diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryDiscriminatorInIdTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryDiscriminatorInIdTest.cs index 6e098c92d28..56282084c14 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryDiscriminatorInIdTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryDiscriminatorInIdTest.cs @@ -261,7 +261,7 @@ public override async Task ReadItem_with_hierarchical_partition_key() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("HierarchicalPartitionKeyEntity", "DerivedHierarchicalPartitionKeyEntity") AND (c["Id"] = 1)) +WHERE (c["$type"] IN ("HierarchicalPartitionKeyEntity", "DerivedHierarchicalPartitionKeyEntity") AND (c["Id"] = "31887258-bdf9-49b8-89b2-01b6aa741a4a")) """); } @@ -286,7 +286,7 @@ public override async Task ReadItem_with_single_partition_key_constant() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 1)) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34")) """); } @@ -312,7 +312,7 @@ public override async Task ReadItem_with_single_partition_key_parameter() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 1)) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34")) """); } @@ -338,7 +338,7 @@ public override async Task ReadItem_with_SingleAsync() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 1)) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34")) OFFSET 0 LIMIT 2 """); } @@ -365,7 +365,7 @@ public override async Task ReadItem_with_inverse_comparison() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (1 = c["Id"])) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ("b29bced8-e1e5-420e-82d7-1c7a51703d34" = c["Id"])) """); } @@ -391,7 +391,7 @@ public override async Task ReadItem_with_EF_Property() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 1)) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34")) """); } @@ -404,7 +404,7 @@ public override async Task ReadItem_with_WithPartitionKey() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 1)) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34")) """); } @@ -428,7 +428,7 @@ public override async Task Multiple_incompatible_predicate_comparisons_cause_no_ """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 1) AND (c["Id"] = 2))) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["Id"] = "3307a33b-7f28-49ef-9857-48f4e3ebcaed"))) """); } @@ -468,7 +468,7 @@ public override async Task ReadItem_is_not_used_without_partition_key() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 1)) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34")) """); } @@ -479,7 +479,7 @@ public override async Task ReadItem_with_non_existent_id() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 999)) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = "50b66960-35be-40c5-bc3d-4c9f2799d4d1")) """); } @@ -491,7 +491,7 @@ public override async Task ReadItem_with_AsNoTracking() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 1)) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34")) """); } @@ -504,7 +504,7 @@ public override async Task ReadItem_with_AsNoTrackingWithIdentityResolution() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 1)) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34")) """); } @@ -745,7 +745,10 @@ public override async Task ReadItem_with_hierarchical_partition_key_leaf() { await base.ReadItem_with_hierarchical_partition_key_leaf(); - AssertSql("""ReadItem(["PK1",1.0,true], DerivedHierarchicalPartitionKeyEntity|11)"""); + AssertSql( + """ +ReadItem(["PK1",1.0,true], DerivedHierarchicalPartitionKeyEntity|316c846c-787f-44b9-aadf-272f1658c5ff) +"""); } public override async Task ReadItem_with_only_hierarchical_partition_key_leaf() @@ -759,7 +762,7 @@ public override async Task ReadItem_with_single_partition_key_constant_leaf() { await base.ReadItem_with_single_partition_key_constant_leaf(); - AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_only_single_partition_key_constant_leaf() @@ -773,7 +776,7 @@ public override async Task ReadItem_with_single_partition_key_parameter_leaf() { await base.ReadItem_with_single_partition_key_parameter_leaf(); - AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_only_single_partition_key_parameter_leaf() @@ -787,7 +790,7 @@ public override async Task ReadItem_with_SingleAsync_leaf() { await base.ReadItem_with_SingleAsync_leaf(); - AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_SingleAsync_with_only_partition_key_leaf() @@ -801,7 +804,7 @@ public override async Task ReadItem_with_inverse_comparison_leaf() { await base.ReadItem_with_inverse_comparison_leaf(); - AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_inverse_comparison_with_only_partition_key_leaf() @@ -815,14 +818,14 @@ public override async Task ReadItem_with_EF_Property_leaf() { await base.ReadItem_with_EF_Property_leaf(); - AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_WithPartitionKey_leaf() { await base.ReadItem_with_WithPartitionKey_leaf(); - AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_WithPartitionKey_with_only_partition_key_leaf() @@ -841,7 +844,7 @@ public override async Task Multiple_incompatible_predicate_comparisons_cause_no_ """ SELECT VALUE c FROM root c -WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 11) AND (c["Id"] = 22))) +WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "188d3253-81be-4a87-b58f-a2bd07e6b98c") AND (c["Id"] = "11f8d1fd-7472-46f5-9e20-16af42b3b8d1"))) """); } @@ -875,7 +878,7 @@ public override async Task ReadItem_is_not_used_without_partition_key_leaf() """ SELECT VALUE c FROM root c -WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 11)) +WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND (c["Id"] = "188d3253-81be-4a87-b58f-a2bd07e6b98c")) """); } @@ -883,21 +886,21 @@ public override async Task ReadItem_with_non_existent_id_leaf() { await base.ReadItem_with_non_existent_id_leaf(); - AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|999)"""); + AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|b964beda-b4e1-4f5c-a729-0a35dae696fe)"""); } public override async Task ReadItem_with_AsNoTracking_leaf() { await base.ReadItem_with_AsNoTracking_leaf(); - AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_AsNoTrackingWithIdentityResolution_leaf() { await base.ReadItem_with_AsNoTrackingWithIdentityResolution_leaf(); - AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_single_explicit_discriminator_mapping() @@ -909,7 +912,7 @@ public override async Task ReadItem_with_single_explicit_discriminator_mapping() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 1) AND (c["$type"] = "SinglePartitionKeyEntity"))) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["$type"] = "SinglePartitionKeyEntity"))) OFFSET 0 LIMIT 2 """); } @@ -923,7 +926,7 @@ public override async Task ReadItem_with_single_explicit_incorrect_discriminator """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 1) AND (c["$type"] = "DerivedSinglePartitionKeyEntity"))) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["$type"] = "DerivedSinglePartitionKeyEntity"))) """); } @@ -938,7 +941,7 @@ public override async Task ReadItem_with_single_explicit_parameterized_discrimin SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 1) AND (c["$type"] = @__discriminator_0))) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["$type"] = @__discriminator_0))) OFFSET 0 LIMIT 2 """); } @@ -947,19 +950,18 @@ public override async Task ReadItem_with_single_explicit_discriminator_mapping_l { await base.ReadItem_with_single_explicit_discriminator_mapping_leaf(); - AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], DerivedSinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_single_explicit_incorrect_discriminator_mapping_leaf() { await base.ReadItem_with_single_explicit_incorrect_discriminator_mapping_leaf(); - // No ReadItem because discriminator value is incorrect AssertSql( """ SELECT VALUE c FROM root c -WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 11) AND (c["$type"] = "SinglePartitionKeyEntity"))) +WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "188d3253-81be-4a87-b58f-a2bd07e6b98c") AND (c["$type"] = "SinglePartitionKeyEntity"))) """); } @@ -974,7 +976,7 @@ public override async Task ReadItem_with_single_explicit_parameterized_discrimin SELECT VALUE c FROM root c -WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 11) AND (c["$type"] = @__discriminator_0))) +WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "188d3253-81be-4a87-b58f-a2bd07e6b98c") AND (c["$type"] = @__discriminator_0))) OFFSET 0 LIMIT 2 """); } diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryFixtureBase.cs b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryFixtureBase.cs index b72b194f4bb..03740b7672c 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryFixtureBase.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryFixtureBase.cs @@ -307,7 +307,7 @@ private static List CreateHierarchicalPartitionK { new HierarchicalPartitionKeyEntity { - Id = 1, + Id = Guid.Parse("31887258-BDF9-49B8-89B2-01B6AA741A4A"), PartitionKey1 = "PK1", PartitionKey2 = 1, PartitionKey3 = true, @@ -315,7 +315,7 @@ private static List CreateHierarchicalPartitionK }, new HierarchicalPartitionKeyEntity { - Id = 1, + Id = Guid.Parse("31887258-BDF9-49B8-89B2-01B6AA741A4A"), // Same Id as previous; different partition. PartitionKey1 = "PK2", PartitionKey2 = 2, PartitionKey3 = false, @@ -323,7 +323,7 @@ private static List CreateHierarchicalPartitionK }, new HierarchicalPartitionKeyEntity { - Id = 2, + Id = Guid.Parse("BBA46A5D-BDB8-40F0-BA80-BA5731147B9A"), // Different Id. PartitionKey1 = "PK1", PartitionKey2 = 1, PartitionKey3 = true, @@ -331,7 +331,7 @@ private static List CreateHierarchicalPartitionK }, new HierarchicalPartitionKeyEntity { - Id = 2, + Id = Guid.Parse("BBA46A5D-BDB8-40F0-BA80-BA5731147B9A"), // Same Id as previous; different partition. PartitionKey1 = "PK2", PartitionKey2 = 2, PartitionKey3 = false, @@ -344,25 +344,25 @@ private static List CreateSinglePartitionKeyEntities() { new SinglePartitionKeyEntity { - Id = 1, + Id = Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34"), PartitionKey = "PK1", Payload = "Payload1" }, new SinglePartitionKeyEntity { - Id = 1, + Id = Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34"), PartitionKey = "PK2", Payload = "Payload2" }, new SinglePartitionKeyEntity { - Id = 2, + Id = Guid.Parse("3307A33B-7F28-49EF-9857-48F4E3EBCAED"), PartitionKey = "PK1", Payload = "Payload3" }, new SinglePartitionKeyEntity { - Id = 2, + Id = Guid.Parse("3307A33B-7F28-49EF-9857-48F4E3EBCAED"), PartitionKey = "PK2", Payload = "Payload4" } @@ -485,7 +485,7 @@ private static List CreateSharedContainerEntities2C public class HierarchicalPartitionKeyEntity { - public int Id { get; set; } + public Guid Id { get; set; } public required string PartitionKey1 { get; set; } public int PartitionKey2 { get; set; } @@ -496,7 +496,7 @@ public class HierarchicalPartitionKeyEntity public class SinglePartitionKeyEntity { - public int Id { get; set; } + public Guid Id { get; set; } public required string PartitionKey { get; set; } diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryInheritanceFixtureBase.cs b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryInheritanceFixtureBase.cs index 474d4737e25..22a4e04521b 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryInheritanceFixtureBase.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryInheritanceFixtureBase.cs @@ -133,7 +133,7 @@ private static List CreateDerivedHierarch { new DerivedHierarchicalPartitionKeyEntity { - Id = 11, + Id = Guid.Parse("316C846C-787F-44B9-AADF-272F1658C5FF"), PartitionKey1 = "PK1", PartitionKey2 = 1, PartitionKey3 = true, @@ -142,7 +142,7 @@ private static List CreateDerivedHierarch }, new DerivedHierarchicalPartitionKeyEntity { - Id = 11, + Id = Guid.Parse("316C846C-787F-44B9-AADF-272F1658C5FF"), // Same Id as previous; different partition. PartitionKey1 = "PK2", PartitionKey2 = 2, PartitionKey3 = false, @@ -151,7 +151,7 @@ private static List CreateDerivedHierarch }, new DerivedHierarchicalPartitionKeyEntity { - Id = 22, + Id = Guid.Parse("C6E8E6D2-F33E-4695-9FA5-D0E9517EF04E"), // New Id. PartitionKey1 = "PK1", PartitionKey2 = 1, PartitionKey3 = true, @@ -160,7 +160,7 @@ private static List CreateDerivedHierarch }, new DerivedHierarchicalPartitionKeyEntity { - Id = 22, + Id = Guid.Parse("C6E8E6D2-F33E-4695-9FA5-D0E9517EF04E"), // Same Id as previous; different partition. PartitionKey1 = "PK2", PartitionKey2 = 2, PartitionKey3 = false, @@ -174,28 +174,28 @@ private static List CreateDerivedSinglePartitio { new DerivedSinglePartitionKeyEntity { - Id = 11, + Id = Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C"), PartitionKey = "PK1", Payload = "Payload1", DerivedPayload = "DerivedPayload1" }, new DerivedSinglePartitionKeyEntity { - Id = 11, + Id = Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C"), PartitionKey = "PK2", Payload = "Payload2", DerivedPayload = "DerivedPayload2" }, new DerivedSinglePartitionKeyEntity { - Id = 22, + Id = Guid.Parse("11F8D1FD-7472-46F5-9E20-16AF42B3B8D1"), PartitionKey = "PK1", Payload = "Payload3", DerivedPayload = "DerivedPayload3" }, new DerivedSinglePartitionKeyEntity { - Id = 22, + Id = Guid.Parse("11F8D1FD-7472-46F5-9E20-16AF42B3B8D1"), PartitionKey = "PK2", Payload = "Payload4", DerivedPayload = "DerivedPayload4" diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryInheritanceTestBase.cs b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryInheritanceTestBase.cs index f79173d7eda..b8c5378f9c5 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryInheritanceTestBase.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryInheritanceTestBase.cs @@ -154,7 +154,11 @@ public virtual Task ReadItem_with_hierarchical_partition_key_leaf() return AssertQuery( async: true, ss => ss.Set() - .Where(e => e.Id == 11 && e.PartitionKey1 == "PK1" && e.PartitionKey2 == partitionKey2 && e.PartitionKey3)); + .Where( + e => e.Id == Guid.Parse("316C846C-787F-44B9-AADF-272F1658C5FF") + && e.PartitionKey1 == "PK1" + && e.PartitionKey2 == partitionKey2 + && e.PartitionKey3)); } [ConditionalFact] @@ -172,7 +176,8 @@ public virtual Task ReadItem_with_only_hierarchical_partition_key_leaf() public virtual Task ReadItem_with_single_partition_key_constant_leaf() => AssertQuery( async: true, - ss => ss.Set().Where(e => e.Id == 11 && e.PartitionKey == "PK1")); + ss => ss.Set() + .Where(e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") && e.PartitionKey == "PK1")); [ConditionalFact] public virtual Task ReadItem_with_only_single_partition_key_constant_leaf() @@ -187,7 +192,8 @@ public virtual Task ReadItem_with_single_partition_key_parameter_leaf() return AssertQuery( async: true, - ss => ss.Set().Where(e => e.Id == 11 && e.PartitionKey == partitionKey)); + ss => ss.Set().Where( + e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") && e.PartitionKey == partitionKey)); } [ConditionalFact] @@ -207,7 +213,8 @@ public virtual Task ReadItem_with_SingleAsync_leaf() return AssertSingle( async: true, - ss => ss.Set().Where(e => e.Id == 11 && e.PartitionKey == partitionKey)); + ss => ss.Set().Where( + e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") && e.PartitionKey == partitionKey)); } [ConditionalFact] @@ -224,7 +231,8 @@ public virtual Task ReadItem_with_SingleAsync_with_only_partition_key_leaf() public virtual Task ReadItem_with_inverse_comparison_leaf() => AssertQuery( async: true, - ss => ss.Set().Where(e => 11 == e.Id && "PK1" == e.PartitionKey)); + ss => ss.Set() + .Where(e => Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") == e.Id && "PK1" == e.PartitionKey)); [ConditionalFact] public virtual Task ReadItem_with_inverse_comparison_with_only_partition_key_leaf() @@ -237,15 +245,17 @@ public virtual Task ReadItem_with_EF_Property_leaf() => AssertQuery( async: true, ss => ss.Set().Where( - e => EF.Property(e, nameof(DerivedSinglePartitionKeyEntity.Id)) == 11 + e => EF.Property(e, nameof(DerivedSinglePartitionKeyEntity.Id)) == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") && EF.Property(e, nameof(DerivedSinglePartitionKeyEntity.PartitionKey)) == "PK1")); [ConditionalFact] public virtual Task ReadItem_with_WithPartitionKey_leaf() => AssertQuery( async: true, - ss => ss.Set().WithPartitionKey("PK1").Where(e => e.Id == 11), - ss => ss.Set().Where(e => e.PartitionKey == "PK1").Where(e => e.Id == 11)); + ss => ss.Set().WithPartitionKey("PK1") + .Where(e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C")), + ss => ss.Set().Where(e => e.PartitionKey == "PK1") + .Where(e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C"))); [ConditionalFact] public virtual Task ReadItem_with_WithPartitionKey_with_only_partition_key_leaf() @@ -261,7 +271,7 @@ public virtual Task Multiple_incompatible_predicate_comparisons_cause_no_ReadIte return AssertQuery( async: true, - ss => ss.Set().Where(e => e.Id == 11 && e.Id == 22 && e.PartitionKey == partitionKey), + ss => ss.Set().Where(e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") && e.Id == Guid.Parse("11F8D1FD-7472-46F5-9E20-16AF42B3B8D1") && e.PartitionKey == partitionKey), assertEmpty: true); } @@ -287,27 +297,29 @@ public virtual Task ReadItem_with_no_partition_key_leaf() public virtual Task ReadItem_is_not_used_without_partition_key_leaf() => AssertQuery( async: true, - ss => ss.Set().Where(e => e.Id == 11)); + ss => ss.Set().Where(e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C"))); [ConditionalFact] public virtual Task ReadItem_with_non_existent_id_leaf() => AssertQuery( async: true, - ss => ss.Set().Where(e => e.Id == 999 && e.PartitionKey == "PK1"), + ss => ss.Set() + .Where(e => e.Id == Guid.Parse("B964BEDA-B4E1-4F5C-A729-0A35DAE696FE") && e.PartitionKey == "PK1"), assertEmpty: true); [ConditionalFact] public virtual Task ReadItem_with_AsNoTracking_leaf() => AssertQuery( async: true, - ss => ss.Set().AsNoTracking().Where(e => e.Id == 11 && e.PartitionKey == "PK1")); + ss => ss.Set().AsNoTracking().Where( + e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") && e.PartitionKey == "PK1")); [ConditionalFact] public virtual Task ReadItem_with_AsNoTrackingWithIdentityResolution_leaf() => AssertQuery( async: true, ss => ss.Set().AsNoTrackingWithIdentityResolution() - .Where(e => e.Id == 11 && e.PartitionKey == "PK1")); + .Where(e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") && e.PartitionKey == "PK1")); [ConditionalFact] public virtual Task ReadItem_with_single_explicit_discriminator_mapping_leaf() @@ -318,11 +330,11 @@ public virtual Task ReadItem_with_single_explicit_discriminator_mapping_leaf() async: true, ss => ss.Set() .Where( - e => e.Id == 11 + e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") && EF.Property(e, "$type") == nameof(DerivedSinglePartitionKeyEntity) && e.PartitionKey == partitionKey), ss => ss.Set() - .Where(e => e.Id == 11 && e.PartitionKey == partitionKey)); + .Where(e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") && e.PartitionKey == partitionKey)); } [ConditionalFact] @@ -334,7 +346,7 @@ public virtual Task ReadItem_with_single_explicit_incorrect_discriminator_mappin async: true, ss => ss.Set() .Where( - e => e.Id == 11 + e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") && EF.Property(e, "$type") == nameof(SinglePartitionKeyEntity) && e.PartitionKey == partitionKey), ss => ss.Set().Where(e => false), @@ -350,7 +362,11 @@ public virtual Task ReadItem_with_single_explicit_parameterized_discriminator_ma return AssertSingle( async: true, ss => ss.Set() - .Where(e => e.Id == 11 && EF.Property(e, "$type") == discriminator && e.PartitionKey == partitionKey), - ss => ss.Set().Where(e => e.Id == 11 && e.PartitionKey == partitionKey)); + .Where( + e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") + && EF.Property(e, "$type") == discriminator + && e.PartitionKey == partitionKey), + ss => ss.Set().Where( + e => e.Id == Guid.Parse("188D3253-81BE-4A87-B58F-A2BD07E6B98C") && e.PartitionKey == partitionKey)); } } diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryNoDiscriminatorInIdTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryNoDiscriminatorInIdTest.cs index f672784f717..14376779590 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryNoDiscriminatorInIdTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryNoDiscriminatorInIdTest.cs @@ -236,7 +236,7 @@ public override async Task ReadItem_with_hierarchical_partition_key() { await base.ReadItem_with_hierarchical_partition_key(); - AssertSql("""ReadItem(["PK1",1.0,true], 1)"""); + AssertSql("""ReadItem(["PK1",1.0,true], 31887258-bdf9-49b8-89b2-01b6aa741a4a)"""); } public override async Task ReadItem_with_only_hierarchical_partition_key() @@ -250,7 +250,7 @@ public override async Task ReadItem_with_single_partition_key_constant() { await base.ReadItem_with_single_partition_key_constant(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_only_single_partition_key_constant() @@ -264,7 +264,7 @@ public override async Task ReadItem_with_single_partition_key_parameter() { await base.ReadItem_with_single_partition_key_parameter(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_only_single_partition_key_parameter() @@ -278,7 +278,7 @@ public override async Task ReadItem_with_SingleAsync() { await base.ReadItem_with_SingleAsync(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_SingleAsync_with_only_partition_key() @@ -292,7 +292,7 @@ public override async Task ReadItem_with_inverse_comparison() { await base.ReadItem_with_inverse_comparison(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_inverse_comparison_with_only_partition_key() @@ -306,14 +306,14 @@ public override async Task ReadItem_with_EF_Property() { await base.ReadItem_with_EF_Property(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_WithPartitionKey() { await base.ReadItem_with_WithPartitionKey(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_WithPartitionKey_with_only_partition_key() @@ -332,7 +332,7 @@ public override async Task Multiple_incompatible_predicate_comparisons_cause_no_ """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 1) AND (c["Id"] = 2))) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["id"] = "3307a33b-7f28-49ef-9857-48f4e3ebcaed"))) """); } @@ -366,7 +366,7 @@ public override async Task ReadItem_is_not_used_without_partition_key() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 1)) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34")) """); } @@ -374,21 +374,21 @@ public override async Task ReadItem_with_non_existent_id() { await base.ReadItem_with_non_existent_id(); - AssertSql("""ReadItem(["PK1"], 999)"""); + AssertSql("""ReadItem(["PK1"], 50b66960-35be-40c5-bc3d-4c9f2799d4d1)"""); } public override async Task ReadItem_with_AsNoTracking() { await base.ReadItem_with_AsNoTracking(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_AsNoTrackingWithIdentityResolution() { await base.ReadItem_with_AsNoTrackingWithIdentityResolution(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_shared_container() @@ -618,7 +618,7 @@ public override async Task ReadItem_with_hierarchical_partition_key_leaf() { await base.ReadItem_with_hierarchical_partition_key_leaf(); - AssertSql("""ReadItem(["PK1",1.0,true], 11)"""); + AssertSql("""ReadItem(["PK1",1.0,true], 316c846c-787f-44b9-aadf-272f1658c5ff)"""); } public override async Task ReadItem_with_only_hierarchical_partition_key_leaf() @@ -632,7 +632,7 @@ public override async Task ReadItem_with_single_partition_key_constant_leaf() { await base.ReadItem_with_single_partition_key_constant_leaf(); - AssertSql("""ReadItem(["PK1"], 11)"""); + AssertSql("""ReadItem(["PK1"], 188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_only_single_partition_key_constant_leaf() @@ -646,7 +646,7 @@ public override async Task ReadItem_with_single_partition_key_parameter_leaf() { await base.ReadItem_with_single_partition_key_parameter_leaf(); - AssertSql("""ReadItem(["PK1"], 11)"""); + AssertSql("""ReadItem(["PK1"], 188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_only_single_partition_key_parameter_leaf() @@ -660,7 +660,7 @@ public override async Task ReadItem_with_SingleAsync_leaf() { await base.ReadItem_with_SingleAsync_leaf(); - AssertSql("""ReadItem(["PK1"], 11)"""); + AssertSql("""ReadItem(["PK1"], 188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_SingleAsync_with_only_partition_key_leaf() @@ -674,7 +674,7 @@ public override async Task ReadItem_with_inverse_comparison_leaf() { await base.ReadItem_with_inverse_comparison_leaf(); - AssertSql("""ReadItem(["PK1"], 11)"""); + AssertSql("""ReadItem(["PK1"], 188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_inverse_comparison_with_only_partition_key_leaf() @@ -688,14 +688,14 @@ public override async Task ReadItem_with_EF_Property_leaf() { await base.ReadItem_with_EF_Property_leaf(); - AssertSql("""ReadItem(["PK1"], 11)"""); + AssertSql("""ReadItem(["PK1"], 188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_WithPartitionKey_leaf() { await base.ReadItem_with_WithPartitionKey_leaf(); - AssertSql("""ReadItem(["PK1"], 11)"""); + AssertSql("""ReadItem(["PK1"], 188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_WithPartitionKey_with_only_partition_key_leaf() @@ -714,7 +714,7 @@ public override async Task Multiple_incompatible_predicate_comparisons_cause_no_ """ SELECT VALUE c FROM root c -WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 11) AND (c["Id"] = 22))) +WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["id"] = "188d3253-81be-4a87-b58f-a2bd07e6b98c") AND (c["id"] = "11f8d1fd-7472-46f5-9e20-16af42b3b8d1"))) """); } @@ -748,7 +748,7 @@ public override async Task ReadItem_is_not_used_without_partition_key_leaf() """ SELECT VALUE c FROM root c -WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 11)) +WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND (c["id"] = "188d3253-81be-4a87-b58f-a2bd07e6b98c")) """); } @@ -756,40 +756,39 @@ public override async Task ReadItem_with_non_existent_id_leaf() { await base.ReadItem_with_non_existent_id_leaf(); - AssertSql("""ReadItem(["PK1"], 999)"""); + AssertSql("""ReadItem(["PK1"], b964beda-b4e1-4f5c-a729-0a35dae696fe)"""); } public override async Task ReadItem_with_AsNoTracking_leaf() { await base.ReadItem_with_AsNoTracking_leaf(); - AssertSql("""ReadItem(["PK1"], 11)"""); + AssertSql("""ReadItem(["PK1"], 188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_AsNoTrackingWithIdentityResolution_leaf() { await base.ReadItem_with_AsNoTrackingWithIdentityResolution_leaf(); - AssertSql("""ReadItem(["PK1"], 11)"""); + AssertSql("""ReadItem(["PK1"], 188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_single_explicit_discriminator_mapping() { await base.ReadItem_with_single_explicit_discriminator_mapping(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_single_explicit_incorrect_discriminator_mapping() { await base.ReadItem_with_single_explicit_incorrect_discriminator_mapping(); - // No ReadItem because discriminator value is incorrect AssertSql( """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 1) AND (c["$type"] = "DerivedSinglePartitionKeyEntity"))) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["$type"] = "DerivedSinglePartitionKeyEntity"))) """); } @@ -797,14 +796,13 @@ public override async Task ReadItem_with_single_explicit_parameterized_discrimin { await base.ReadItem_with_single_explicit_parameterized_discriminator_mapping(); - // No ReadItem because discriminator check is parameterized AssertSql( """ @__discriminator_0='SinglePartitionKeyEntity' SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 1) AND (c["$type"] = @__discriminator_0))) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["$type"] = @__discriminator_0))) OFFSET 0 LIMIT 2 """); } @@ -813,7 +811,7 @@ public override async Task ReadItem_with_single_explicit_discriminator_mapping_l { await base.ReadItem_with_single_explicit_discriminator_mapping_leaf(); - AssertSql("""ReadItem(["PK1"], 11)"""); + AssertSql("""ReadItem(["PK1"], 188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_single_explicit_incorrect_discriminator_mapping_leaf() @@ -825,7 +823,7 @@ public override async Task ReadItem_with_single_explicit_incorrect_discriminator """ SELECT VALUE c FROM root c -WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 11) AND (c["$type"] = "SinglePartitionKeyEntity"))) +WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["id"] = "188d3253-81be-4a87-b58f-a2bd07e6b98c") AND (c["$type"] = "SinglePartitionKeyEntity"))) """); } @@ -840,7 +838,7 @@ public override async Task ReadItem_with_single_explicit_parameterized_discrimin SELECT VALUE c FROM root c -WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 11) AND (c["$type"] = @__discriminator_0))) +WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["id"] = "188d3253-81be-4a87-b58f-a2bd07e6b98c") AND (c["$type"] = @__discriminator_0))) OFFSET 0 LIMIT 2 """); } diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryRootDiscriminatorInIdTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryRootDiscriminatorInIdTest.cs index 8e0e574a193..f65ca71a1ef 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryRootDiscriminatorInIdTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryRootDiscriminatorInIdTest.cs @@ -238,7 +238,7 @@ public override async Task ReadItem_with_hierarchical_partition_key() { await base.ReadItem_with_hierarchical_partition_key(); - AssertSql("""ReadItem(["PK1",1.0,true], HierarchicalPartitionKeyEntity|1)"""); + AssertSql("""ReadItem(["PK1",1.0,true], HierarchicalPartitionKeyEntity|31887258-bdf9-49b8-89b2-01b6aa741a4a)"""); } public override async Task ReadItem_with_only_hierarchical_partition_key() @@ -252,7 +252,7 @@ public override async Task ReadItem_with_single_partition_key_constant() { await base.ReadItem_with_single_partition_key_constant(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|1)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_only_single_partition_key_constant() @@ -266,7 +266,7 @@ public override async Task ReadItem_with_single_partition_key_parameter() { await base.ReadItem_with_single_partition_key_parameter(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|1)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_only_single_partition_key_parameter() @@ -280,7 +280,7 @@ public override async Task ReadItem_with_SingleAsync() { await base.ReadItem_with_SingleAsync(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|1)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_SingleAsync_with_only_partition_key() @@ -294,7 +294,7 @@ public override async Task ReadItem_with_inverse_comparison() { await base.ReadItem_with_inverse_comparison(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|1)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_inverse_comparison_with_only_partition_key() @@ -308,14 +308,14 @@ public override async Task ReadItem_with_EF_Property() { await base.ReadItem_with_EF_Property(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|1)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_WithPartitionKey() { await base.ReadItem_with_WithPartitionKey(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|1)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_WithPartitionKey_with_only_partition_key() @@ -334,7 +334,7 @@ public override async Task Multiple_incompatible_predicate_comparisons_cause_no_ """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 1) AND (c["Id"] = 2))) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["Id"] = "3307a33b-7f28-49ef-9857-48f4e3ebcaed"))) """); } @@ -368,7 +368,7 @@ public override async Task ReadItem_is_not_used_without_partition_key() """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 1)) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND (c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34")) """); } @@ -376,21 +376,21 @@ public override async Task ReadItem_with_non_existent_id() { await base.ReadItem_with_non_existent_id(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|999)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|50b66960-35be-40c5-bc3d-4c9f2799d4d1)"""); } public override async Task ReadItem_with_AsNoTracking() { await base.ReadItem_with_AsNoTracking(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|1)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_AsNoTrackingWithIdentityResolution() { await base.ReadItem_with_AsNoTrackingWithIdentityResolution(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|1)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_shared_container() @@ -622,7 +622,7 @@ public override async Task ReadItem_with_hierarchical_partition_key_leaf() { await base.ReadItem_with_hierarchical_partition_key_leaf(); - AssertSql("""ReadItem(["PK1",1.0,true], HierarchicalPartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1",1.0,true], HierarchicalPartitionKeyEntity|316c846c-787f-44b9-aadf-272f1658c5ff)"""); } public override async Task ReadItem_with_only_hierarchical_partition_key_leaf() @@ -636,7 +636,7 @@ public override async Task ReadItem_with_single_partition_key_constant_leaf() { await base.ReadItem_with_single_partition_key_constant_leaf(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_only_single_partition_key_constant_leaf() @@ -650,7 +650,7 @@ public override async Task ReadItem_with_single_partition_key_parameter_leaf() { await base.ReadItem_with_single_partition_key_parameter_leaf(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_only_single_partition_key_parameter_leaf() @@ -664,7 +664,7 @@ public override async Task ReadItem_with_SingleAsync_leaf() { await base.ReadItem_with_SingleAsync_leaf(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_SingleAsync_with_only_partition_key_leaf() @@ -678,7 +678,7 @@ public override async Task ReadItem_with_inverse_comparison_leaf() { await base.ReadItem_with_inverse_comparison_leaf(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_inverse_comparison_with_only_partition_key_leaf() @@ -692,14 +692,14 @@ public override async Task ReadItem_with_EF_Property_leaf() { await base.ReadItem_with_EF_Property_leaf(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_WithPartitionKey_leaf() { await base.ReadItem_with_WithPartitionKey_leaf(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_WithPartitionKey_with_only_partition_key_leaf() @@ -718,7 +718,7 @@ public override async Task Multiple_incompatible_predicate_comparisons_cause_no_ """ SELECT VALUE c FROM root c -WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 11) AND (c["Id"] = 22))) +WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "188d3253-81be-4a87-b58f-a2bd07e6b98c") AND (c["Id"] = "11f8d1fd-7472-46f5-9e20-16af42b3b8d1"))) """); } @@ -752,7 +752,7 @@ public override async Task ReadItem_is_not_used_without_partition_key_leaf() """ SELECT VALUE c FROM root c -WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND (c["Id"] = 11)) +WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND (c["Id"] = "188d3253-81be-4a87-b58f-a2bd07e6b98c")) """); } @@ -760,28 +760,28 @@ public override async Task ReadItem_with_non_existent_id_leaf() { await base.ReadItem_with_non_existent_id_leaf(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|999)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|b964beda-b4e1-4f5c-a729-0a35dae696fe)"""); } public override async Task ReadItem_with_AsNoTracking_leaf() { await base.ReadItem_with_AsNoTracking_leaf(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_AsNoTrackingWithIdentityResolution_leaf() { await base.ReadItem_with_AsNoTrackingWithIdentityResolution_leaf(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_single_explicit_discriminator_mapping() { await base.ReadItem_with_single_explicit_discriminator_mapping(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|1)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_single_explicit_incorrect_discriminator_mapping() @@ -793,7 +793,7 @@ public override async Task ReadItem_with_single_explicit_incorrect_discriminator """ SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 1) AND (c["$type"] = "DerivedSinglePartitionKeyEntity"))) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["$type"] = "DerivedSinglePartitionKeyEntity"))) """); } @@ -808,7 +808,7 @@ public override async Task ReadItem_with_single_explicit_parameterized_discrimin SELECT VALUE c FROM root c -WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 1) AND (c["$type"] = @__discriminator_0))) +WHERE (c["$type"] IN ("SinglePartitionKeyEntity", "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["$type"] = @__discriminator_0))) OFFSET 0 LIMIT 2 """); } @@ -817,7 +817,7 @@ public override async Task ReadItem_with_single_explicit_discriminator_mapping_l { await base.ReadItem_with_single_explicit_discriminator_mapping_leaf(); - AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|11)"""); + AssertSql("""ReadItem(["PK1"], SinglePartitionKeyEntity|188d3253-81be-4a87-b58f-a2bd07e6b98c)"""); } public override async Task ReadItem_with_single_explicit_incorrect_discriminator_mapping_leaf() @@ -829,7 +829,7 @@ public override async Task ReadItem_with_single_explicit_incorrect_discriminator """ SELECT VALUE c FROM root c -WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 11) AND (c["$type"] = "SinglePartitionKeyEntity"))) +WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "188d3253-81be-4a87-b58f-a2bd07e6b98c") AND (c["$type"] = "SinglePartitionKeyEntity"))) """); } @@ -844,7 +844,7 @@ public override async Task ReadItem_with_single_explicit_parameterized_discrimin SELECT VALUE c FROM root c -WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = 11) AND (c["$type"] = @__discriminator_0))) +WHERE ((c["$type"] = "DerivedSinglePartitionKeyEntity") AND ((c["Id"] = "188d3253-81be-4a87-b58f-a2bd07e6b98c") AND (c["$type"] = @__discriminator_0))) OFFSET 0 LIMIT 2 """); } diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryTest.cs index b31eb485e6e..a5bf0e45536 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryTest.cs @@ -234,7 +234,7 @@ public override async Task ReadItem_with_hierarchical_partition_key() { await base.ReadItem_with_hierarchical_partition_key(); - AssertSql("""ReadItem(["PK1",1.0,true], 1)"""); + AssertSql("""ReadItem(["PK1",1.0,true], 31887258-bdf9-49b8-89b2-01b6aa741a4a)"""); } public override async Task ReadItem_with_only_hierarchical_partition_key() @@ -248,7 +248,7 @@ public override async Task ReadItem_with_single_partition_key_constant() { await base.ReadItem_with_single_partition_key_constant(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_only_single_partition_key_constant() @@ -262,7 +262,7 @@ public override async Task ReadItem_with_single_partition_key_parameter() { await base.ReadItem_with_single_partition_key_parameter(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_only_single_partition_key_parameter() @@ -276,7 +276,7 @@ public override async Task ReadItem_with_SingleAsync() { await base.ReadItem_with_SingleAsync(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_SingleAsync_with_only_partition_key() @@ -290,7 +290,7 @@ public override async Task ReadItem_with_inverse_comparison() { await base.ReadItem_with_inverse_comparison(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_inverse_comparison_with_only_partition_key() @@ -304,14 +304,14 @@ public override async Task ReadItem_with_EF_Property() { await base.ReadItem_with_EF_Property(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_WithPartitionKey() { await base.ReadItem_with_WithPartitionKey(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_WithPartitionKey_with_only_partition_key() @@ -330,7 +330,7 @@ public override async Task Multiple_incompatible_predicate_comparisons_cause_no_ """ SELECT VALUE c FROM root c -WHERE ((c["Id"] = 1) AND (c["Id"] = 2)) +WHERE ((c["id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["id"] = "3307a33b-7f28-49ef-9857-48f4e3ebcaed")) """); } @@ -365,7 +365,7 @@ public override async Task ReadItem_is_not_used_without_partition_key() """ SELECT VALUE c FROM root c -WHERE (c["Id"] = 1) +WHERE (c["id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") """); } @@ -373,21 +373,21 @@ public override async Task ReadItem_with_non_existent_id() { await base.ReadItem_with_non_existent_id(); - AssertSql("""ReadItem(["PK1"], 999)"""); + AssertSql("""ReadItem(["PK1"], 50b66960-35be-40c5-bc3d-4c9f2799d4d1)"""); } public override async Task ReadItem_with_AsNoTracking() { await base.ReadItem_with_AsNoTracking(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_AsNoTrackingWithIdentityResolution() { await base.ReadItem_with_AsNoTrackingWithIdentityResolution(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_shared_container() @@ -415,7 +415,7 @@ public override async Task ReadItem_with_single_explicit_discriminator_mapping() { await base.ReadItem_with_single_explicit_discriminator_mapping(); - AssertSql("""ReadItem(["PK1"], 1)"""); + AssertSql("""ReadItem(["PK1"], b29bced8-e1e5-420e-82d7-1c7a51703d34)"""); } public override async Task ReadItem_with_single_explicit_incorrect_discriminator_mapping() @@ -427,7 +427,7 @@ public override async Task ReadItem_with_single_explicit_incorrect_discriminator """ SELECT VALUE c FROM root c -WHERE ((c["Id"] = 1) AND (c["$type"] = "DerivedSinglePartitionKeyEntity")) +WHERE ((c["id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["$type"] = "DerivedSinglePartitionKeyEntity")) """); } @@ -435,14 +435,13 @@ public override async Task ReadItem_with_single_explicit_parameterized_discrimin { await base.ReadItem_with_single_explicit_parameterized_discriminator_mapping(); - // No ReadItem because discriminator check is parameterized AssertSql( """ @__discriminator_0='SinglePartitionKeyEntity' SELECT VALUE c FROM root c -WHERE ((c["Id"] = 1) AND (c["$type"] = @__discriminator_0)) +WHERE ((c["id"] = "b29bced8-e1e5-420e-82d7-1c7a51703d34") AND (c["$type"] = @__discriminator_0)) OFFSET 0 LIMIT 2 """); } diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryTestBase.cs b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryTestBase.cs index 5a0bedaf279..e2c1bc33712 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryTestBase.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryTestBase.cs @@ -161,7 +161,11 @@ public virtual Task ReadItem_with_hierarchical_partition_key() return AssertQuery( async: true, ss => ss.Set() - .Where(e => e.Id == 1 && e.PartitionKey1 == "PK1" && e.PartitionKey2 == partitionKey2 && e.PartitionKey3)); + .Where( + e => e.Id == Guid.Parse("31887258-BDF9-49B8-89B2-01B6AA741A4A") + && e.PartitionKey1 == "PK1" + && e.PartitionKey2 == partitionKey2 + && e.PartitionKey3)); } [ConditionalFact] @@ -179,7 +183,8 @@ public virtual Task ReadItem_with_only_hierarchical_partition_key() public virtual Task ReadItem_with_single_partition_key_constant() => AssertQuery( async: true, - ss => ss.Set().Where(e => e.Id == 1 && e.PartitionKey == "PK1")); + ss => ss.Set() + .Where(e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") && e.PartitionKey == "PK1")); [ConditionalFact] public virtual Task ReadItem_with_only_single_partition_key_constant() @@ -194,7 +199,8 @@ public virtual Task ReadItem_with_single_partition_key_parameter() return AssertQuery( async: true, - ss => ss.Set().Where(e => e.Id == 1 && e.PartitionKey == partitionKey)); + ss => ss.Set().Where( + e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") && e.PartitionKey == partitionKey)); } [ConditionalFact] @@ -214,7 +220,8 @@ public virtual Task ReadItem_with_SingleAsync() return AssertSingle( async: true, - ss => ss.Set().Where(e => e.Id == 1 && e.PartitionKey == partitionKey)); + ss => ss.Set().Where( + e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") && e.PartitionKey == partitionKey)); } [ConditionalFact] @@ -231,7 +238,8 @@ public virtual Task ReadItem_with_SingleAsync_with_only_partition_key() public virtual Task ReadItem_with_inverse_comparison() => AssertQuery( async: true, - ss => ss.Set().Where(e => 1 == e.Id && "PK1" == e.PartitionKey)); + ss => ss.Set() + .Where(e => Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") == e.Id && "PK1" == e.PartitionKey)); [ConditionalFact] public virtual Task ReadItem_with_inverse_comparison_with_only_partition_key() @@ -244,15 +252,17 @@ public virtual Task ReadItem_with_EF_Property() => AssertQuery( async: true, ss => ss.Set().Where( - e => EF.Property(e, nameof(SinglePartitionKeyEntity.Id)) == 1 + e => EF.Property(e, nameof(SinglePartitionKeyEntity.Id)) == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") && EF.Property(e, nameof(SinglePartitionKeyEntity.PartitionKey)) == "PK1")); [ConditionalFact] public virtual Task ReadItem_with_WithPartitionKey() => AssertQuery( async: true, - ss => ss.Set().WithPartitionKey("PK1").Where(e => e.Id == 1), - ss => ss.Set().Where(e => e.PartitionKey == "PK1").Where(e => e.Id == 1)); + ss => ss.Set().WithPartitionKey("PK1") + .Where(e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34")), + ss => ss.Set().Where(e => e.PartitionKey == "PK1") + .Where(e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34"))); [ConditionalFact] public virtual Task ReadItem_with_WithPartitionKey_with_only_partition_key() @@ -268,7 +278,10 @@ public virtual Task Multiple_incompatible_predicate_comparisons_cause_no_ReadIte return AssertQuery( async: true, - ss => ss.Set().Where(e => e.Id == 1 && e.Id == 2 && e.PartitionKey == partitionKey), + ss => ss.Set().Where( + e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") + && e.Id == Guid.Parse("3307A33B-7F28-49EF-9857-48F4E3EBCAED") + && e.PartitionKey == partitionKey), assertEmpty: true); } @@ -294,26 +307,26 @@ public virtual Task ReadItem_with_no_partition_key() public virtual Task ReadItem_is_not_used_without_partition_key() => AssertQuery( async: true, - ss => ss.Set().Where(e => e.Id == 1)); + ss => ss.Set().Where(e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34"))); [ConditionalFact] public virtual Task ReadItem_with_non_existent_id() => AssertQuery( async: true, - ss => ss.Set().Where(e => e.Id == 999 && e.PartitionKey == "PK1"), + ss => ss.Set().Where(e => e.Id == Guid.Parse("50B66960-35BE-40C5-BC3D-4C9F2799D4D1") && e.PartitionKey == "PK1"), assertEmpty: true); [ConditionalFact] public virtual Task ReadItem_with_AsNoTracking() => AssertQuery( async: true, - ss => ss.Set().AsNoTracking().Where(e => e.Id == 1 && e.PartitionKey == "PK1")); + ss => ss.Set().AsNoTracking().Where(e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") && e.PartitionKey == "PK1")); [ConditionalFact] public virtual Task ReadItem_with_AsNoTrackingWithIdentityResolution() => AssertQuery( async: true, - ss => ss.Set().AsNoTrackingWithIdentityResolution().Where(e => e.Id == 1 && e.PartitionKey == "PK1")); + ss => ss.Set().AsNoTrackingWithIdentityResolution().Where(e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") && e.PartitionKey == "PK1")); [ConditionalFact] public virtual Task ReadItem_with_shared_container() @@ -342,11 +355,11 @@ public virtual Task ReadItem_with_single_explicit_discriminator_mapping() async: true, ss => ss.Set() .Where( - e => e.Id == 1 + e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") && EF.Property(e, "$type") == nameof(SinglePartitionKeyEntity) && e.PartitionKey == partitionKey), ss => ss.Set() - .Where(e => e.Id == 1 && e.PartitionKey == partitionKey)); + .Where(e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") && e.PartitionKey == partitionKey)); } [ConditionalFact] @@ -358,7 +371,7 @@ public virtual Task ReadItem_with_single_explicit_incorrect_discriminator_mappin async: true, ss => ss.Set() .Where( - e => e.Id == 1 + e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") && EF.Property(e, "$type") == nameof(DerivedSinglePartitionKeyEntity) && e.PartitionKey == partitionKey), ss => ss.Set().Where(e => false), @@ -374,8 +387,12 @@ public virtual Task ReadItem_with_single_explicit_parameterized_discriminator_ma return AssertSingle( async: true, ss => ss.Set() - .Where(e => e.Id == 1 && EF.Property(e, "$type") == discriminator && e.PartitionKey == partitionKey), - ss => ss.Set().Where(e => e.Id == 1 && e.PartitionKey == partitionKey)); + .Where( + e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") + && EF.Property(e, "$type") == discriminator + && e.PartitionKey == partitionKey), + ss => ss.Set().Where( + e => e.Id == Guid.Parse("B29BCED8-E1E5-420E-82D7-1C7A51703D34") && e.PartitionKey == partitionKey)); } protected void AssertSql(params string[] expected) From ce019ce6e7a26292187de6bf1b21fd5a1712b6da Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 14:28:20 +0000 Subject: [PATCH 26/32] Update dependencies from https://github.com/dotnet/arcade build 20240829.5 (#34597) [release/9.0] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 2 +- global.json | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 996ae4981cd..8d0d17f1dee 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -55,17 +55,17 @@ - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + d21db44e84b9038ea7b2add139adee2303d46800 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + d21db44e84b9038ea7b2add139adee2303d46800 - + https://github.com/dotnet/arcade - 91599268652b51969b8d8088d4f2f2ba7b3ebb19 + d21db44e84b9038ea7b2add139adee2303d46800 diff --git a/eng/Versions.props b/eng/Versions.props index 2cb258c3402..d963f52dc40 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -30,7 +30,7 @@ 9.0.0-rc.2.24423.10 - 9.0.0-beta.24423.2 + 9.0.0-beta.24429.5 17.9.5 diff --git a/global.json b/global.json index 2dfd6cb7cf1..108c2c01e2f 100644 --- a/global.json +++ b/global.json @@ -13,7 +13,7 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24423.2", - "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24423.2" + "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24429.5", + "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24429.5" } } From 2717558288868da12240083017f395b02d168fc1 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 14:44:10 +0000 Subject: [PATCH 27/32] Update dependencies from https://github.com/dotnet/runtime build 20240829.19 (#34598) [release/9.0] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 48 ++++++++++++++++++++--------------------- eng/Versions.props | 24 ++++++++++----------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 8d0d17f1dee..aec5517a8fb 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,57 +1,57 @@ - + https://github.com/dotnet/runtime - 6f23d04dc2b2039e9eaf97bee2ac02a77ce56b21 + d0f3235d312f7cf9683012b3fe96b2c6f20a1743 - + https://github.com/dotnet/runtime - 6f23d04dc2b2039e9eaf97bee2ac02a77ce56b21 + d0f3235d312f7cf9683012b3fe96b2c6f20a1743 - + https://github.com/dotnet/runtime - 6f23d04dc2b2039e9eaf97bee2ac02a77ce56b21 + d0f3235d312f7cf9683012b3fe96b2c6f20a1743 - + https://github.com/dotnet/runtime - 6f23d04dc2b2039e9eaf97bee2ac02a77ce56b21 + d0f3235d312f7cf9683012b3fe96b2c6f20a1743 - + https://github.com/dotnet/runtime - 6f23d04dc2b2039e9eaf97bee2ac02a77ce56b21 + d0f3235d312f7cf9683012b3fe96b2c6f20a1743 - + https://github.com/dotnet/runtime - 6f23d04dc2b2039e9eaf97bee2ac02a77ce56b21 + d0f3235d312f7cf9683012b3fe96b2c6f20a1743 - + https://github.com/dotnet/runtime - 6f23d04dc2b2039e9eaf97bee2ac02a77ce56b21 + d0f3235d312f7cf9683012b3fe96b2c6f20a1743 - + https://github.com/dotnet/runtime - 6f23d04dc2b2039e9eaf97bee2ac02a77ce56b21 + d0f3235d312f7cf9683012b3fe96b2c6f20a1743 - + https://github.com/dotnet/runtime - 6f23d04dc2b2039e9eaf97bee2ac02a77ce56b21 + d0f3235d312f7cf9683012b3fe96b2c6f20a1743 - + https://github.com/dotnet/runtime - 6f23d04dc2b2039e9eaf97bee2ac02a77ce56b21 + d0f3235d312f7cf9683012b3fe96b2c6f20a1743 - + https://github.com/dotnet/runtime - 6f23d04dc2b2039e9eaf97bee2ac02a77ce56b21 + d0f3235d312f7cf9683012b3fe96b2c6f20a1743 - + https://github.com/dotnet/runtime - 6f23d04dc2b2039e9eaf97bee2ac02a77ce56b21 + d0f3235d312f7cf9683012b3fe96b2c6f20a1743 diff --git a/eng/Versions.props b/eng/Versions.props index d963f52dc40..f22b3095840 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -16,18 +16,18 @@ False - 9.0.0-rc.2.24423.10 - 9.0.0-rc.2.24423.10 - 9.0.0-rc.2.24423.10 - 9.0.0-rc.2.24423.10 - 9.0.0-rc.2.24423.10 - 9.0.0-rc.2.24423.10 - 9.0.0-rc.2.24423.10 - 9.0.0-rc.2.24423.10 - 9.0.0-rc.2.24423.10 - 9.0.0-rc.2.24423.10 - 9.0.0-rc.2.24423.10 - 9.0.0-rc.2.24423.10 + 9.0.0-rc.2.24429.19 + 9.0.0-rc.2.24429.19 + 9.0.0-rc.2.24429.19 + 9.0.0-rc.2.24429.19 + 9.0.0-rc.2.24429.19 + 9.0.0-rc.2.24429.19 + 9.0.0-rc.2.24429.19 + 9.0.0-rc.2.24429.19 + 9.0.0-rc.2.24429.19 + 9.0.0-rc.2.24429.19 + 9.0.0-rc.2.24429.19 + 9.0.0-rc.2.24429.19 9.0.0-beta.24429.5 From 972a50aed052de667463b2eb260d875171455cfc Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Mon, 2 Sep 2024 18:54:32 -0700 Subject: [PATCH 28/32] [release/9.0] Acquire the migrations database lock in a transaction. (#34489) Reacquire the lock when retrying. Execute all migrations in a single transaction. Fixes #34439 Fixes #34569 --- .../Diagnostics/RelationalEventId.cs | 14 + .../Diagnostics/RelationalLoggerExtensions.cs | 30 ++ .../RelationalLoggingDefinitions.cs | 9 + .../Migrations/HistoryRepository.cs | 72 +++-- .../HistoryRepositoryDependencies.cs | 9 +- .../Migrations/IHistoryRepository.cs | 49 +++- .../Migrations/IMigrationCommandExecutor.cs | 42 +++ .../Migrations/IMigrationsDatabaseLock.cs | 62 +++++ .../Internal/MigrationCommandExecutor.cs | 257 ++++++++++++------ .../Migrations/Internal/Migrator.cs | 253 ++++++++++++++--- .../Migrations/LockReleaseBehavior.cs | 25 ++ .../Migrations/MigrationExecutionState.cs | 35 +++ .../Properties/RelationalStrings.Designer.cs | 29 +- .../Properties/RelationalStrings.resx | 58 ++-- .../Storage/RelationalDatabaseCreator.cs | 4 +- .../Internal/SqlServerHistoryRepository.cs | 19 +- .../SqlServerMigrationDatabaseLock.cs | 17 +- .../Internal/SqlServerDatabaseCreator.cs | 44 ++- .../Internal/SqliteHistoryRepository.cs | 31 ++- .../Internal/SqliteMigrationDatabaseLock.cs | 17 +- .../Design/DesignTimeServicesTest.cs | 12 +- .../Design/MigrationScaffolderTest.cs | 9 +- .../RelationalDatabaseFacadeExtensionsTest.cs | 6 +- .../MigrationsInfrastructureSqlServerTest.cs | 65 ++++- .../TestSqlServerRetryingExecutionStrategy.cs | 7 + 25 files changed, 928 insertions(+), 247 deletions(-) create mode 100644 src/EFCore.Relational/Migrations/IMigrationsDatabaseLock.cs create mode 100644 src/EFCore.Relational/Migrations/LockReleaseBehavior.cs create mode 100644 src/EFCore.Relational/Migrations/MigrationExecutionState.cs diff --git a/src/EFCore.Relational/Diagnostics/RelationalEventId.cs b/src/EFCore.Relational/Diagnostics/RelationalEventId.cs index cabde564e20..c05c73c46a3 100644 --- a/src/EFCore.Relational/Diagnostics/RelationalEventId.cs +++ b/src/EFCore.Relational/Diagnostics/RelationalEventId.cs @@ -80,6 +80,7 @@ private enum Id PendingModelChangesWarning, NonTransactionalMigrationOperationWarning, AcquiringMigrationLock, + MigrationsUserTransactionWarning, // Query events QueryClientEvaluationWarning = CoreEventId.RelationalBaseId + 500, @@ -764,6 +765,19 @@ private static EventId MakeMigrationsId(Id id) /// public static readonly EventId AcquiringMigrationLock = MakeMigrationsId(Id.AcquiringMigrationLock); + /// + /// A migration lock is being acquired. + /// + /// + /// + /// This event is in the category. + /// + /// + /// This event uses the payload when used with a . + /// + /// + public static readonly EventId MigrationsUserTransactionWarning = MakeMigrationsId(Id.MigrationsUserTransactionWarning); + private static readonly string _queryPrefix = DbLoggerCategory.Query.Name + "."; private static EventId MakeQueryId(Id id) diff --git a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs index a8afec569e1..177b7e90bba 100644 --- a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs +++ b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs @@ -2425,6 +2425,36 @@ private static string AcquiringMigrationLock(EventDefinitionBase definition, Eve return d.GenerateMessage(); } + /// + /// Logs for the event. + /// + /// The diagnostics logger to use. + public static void MigrationsUserTransactionWarning( + this IDiagnosticsLogger diagnostics) + { + var definition = RelationalResources.LogMigrationsUserTransaction(diagnostics); + + if (diagnostics.ShouldLog(definition)) + { + definition.Log(diagnostics); + } + + if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled)) + { + var eventData = new EventData( + definition, + MigrationsUserTransactionWarning); + + diagnostics.DispatchEventData(definition, eventData, diagnosticSourceEnabled, simpleLogEnabled); + } + } + + private static string MigrationsUserTransactionWarning(EventDefinitionBase definition, EventData payload) + { + var d = (EventDefinition)definition; + return d.GenerateMessage(); + } + /// /// Logs for the event. /// diff --git a/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs b/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs index 9b57a07998e..762172c8944 100644 --- a/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs +++ b/src/EFCore.Relational/Diagnostics/RelationalLoggingDefinitions.cs @@ -367,6 +367,15 @@ public abstract class RelationalLoggingDefinitions : LoggingDefinitions [EntityFrameworkInternal] public EventDefinitionBase? LogAcquiringMigrationLock; + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] + public EventDefinitionBase? LogMigrationsUserTransactionWarning; + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in diff --git a/src/EFCore.Relational/Migrations/HistoryRepository.cs b/src/EFCore.Relational/Migrations/HistoryRepository.cs index 78dc3b24013..bfb565786c0 100644 --- a/src/EFCore.Relational/Migrations/HistoryRepository.cs +++ b/src/EFCore.Relational/Migrations/HistoryRepository.cs @@ -47,6 +47,14 @@ protected HistoryRepository(HistoryRepositoryDependencies dependencies) TableSchema = relationalOptions.MigrationsHistoryTableSchema; } + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public abstract LockReleaseBehavior LockReleaseBehavior { get; } + /// /// Relational provider-specific dependencies for this service. /// @@ -120,14 +128,15 @@ protected virtual string ProductVersionColumnName /// /// if the table already exists, otherwise. public virtual bool Exists() - => InterpretExistsResult( - Dependencies.RawSqlCommandBuilder.Build(ExistsSql).ExecuteScalar( - new RelationalCommandParameterObject( - Dependencies.Connection, - null, - null, - Dependencies.CurrentContext.Context, - Dependencies.CommandLogger, CommandSource.Migrations))); + => Dependencies.DatabaseCreator.Exists() + && InterpretExistsResult( + Dependencies.RawSqlCommandBuilder.Build(ExistsSql).ExecuteScalar( + new RelationalCommandParameterObject( + Dependencies.Connection, + null, + null, + Dependencies.CurrentContext.Context, + Dependencies.CommandLogger, CommandSource.Migrations))); /// /// Checks whether or not the history table exists. @@ -139,15 +148,16 @@ public virtual bool Exists() /// /// If the is canceled. public virtual async Task ExistsAsync(CancellationToken cancellationToken = default) - => InterpretExistsResult( - await Dependencies.RawSqlCommandBuilder.Build(ExistsSql).ExecuteScalarAsync( - new RelationalCommandParameterObject( - Dependencies.Connection, - null, - null, - Dependencies.CurrentContext.Context, - Dependencies.CommandLogger, CommandSource.Migrations), - cancellationToken).ConfigureAwait(false)); + => await Dependencies.DatabaseCreator.ExistsAsync(cancellationToken).ConfigureAwait(false) + && InterpretExistsResult( + await Dependencies.RawSqlCommandBuilder.Build(ExistsSql).ExecuteScalarAsync( + new RelationalCommandParameterObject( + Dependencies.Connection, + null, + null, + Dependencies.CurrentContext.Context, + Dependencies.CommandLogger, CommandSource.Migrations), + cancellationToken).ConfigureAwait(false)); /// /// Interprets the result of executing . @@ -173,13 +183,15 @@ public virtual string GetCreateScript() /// Creates the history table. /// public virtual void Create() - => Dependencies.MigrationCommandExecutor.ExecuteNonQuery(GetCreateCommands(), Dependencies.Connection); + => Dependencies.MigrationCommandExecutor.ExecuteNonQuery( + GetCreateCommands(), Dependencies.Connection, new MigrationExecutionState(), commitTransaction: true); /// /// Creates the history table. /// public virtual Task CreateAsync(CancellationToken cancellationToken = default) - => Dependencies.MigrationCommandExecutor.ExecuteNonQueryAsync(GetCreateCommands(), Dependencies.Connection, cancellationToken); + => Dependencies.MigrationCommandExecutor.ExecuteNonQueryAsync( + GetCreateCommands(), Dependencies.Connection, new MigrationExecutionState(), commitTransaction: true, cancellationToken: cancellationToken); /// /// Returns the migration commands that will create the history table. @@ -194,19 +206,37 @@ protected virtual IReadOnlyList GetCreateCommands() return commandList; } + bool IHistoryRepository.CreateIfNotExists() + => Dependencies.MigrationCommandExecutor.ExecuteNonQuery( + GetCreateIfNotExistsCommands(), Dependencies.Connection, new MigrationExecutionState(), commitTransaction: true) + != 0; + + async Task IHistoryRepository.CreateIfNotExistsAsync(CancellationToken cancellationToken) + => (await Dependencies.MigrationCommandExecutor.ExecuteNonQueryAsync( + GetCreateIfNotExistsCommands(), Dependencies.Connection, new MigrationExecutionState(), commitTransaction: true, cancellationToken: cancellationToken).ConfigureAwait(false)) + != 0; + + private IReadOnlyList GetCreateIfNotExistsCommands() + => Dependencies.MigrationsSqlGenerator.Generate([new SqlOperation + { + Sql = GetCreateIfNotExistsScript(), + SuppressTransaction = true + }]); + /// /// Gets an exclusive lock on the database. /// /// An object that can be disposed to release the lock. - public abstract IDisposable GetDatabaseLock(); + public abstract IMigrationsDatabaseLock AcquireDatabaseLock(); /// /// Gets an exclusive lock on the database. /// /// A to observe while waiting for the task to complete. + /// /// An object that can be disposed to release the lock. /// If the is canceled. - public abstract Task GetDatabaseLockAsync(CancellationToken cancellationToken = default); + public abstract Task AcquireDatabaseLockAsync(CancellationToken cancellationToken = default); /// /// Configures the entity type mapped to the history table. diff --git a/src/EFCore.Relational/Migrations/HistoryRepositoryDependencies.cs b/src/EFCore.Relational/Migrations/HistoryRepositoryDependencies.cs index b5f40bd8ba2..a8bf28d3f22 100644 --- a/src/EFCore.Relational/Migrations/HistoryRepositoryDependencies.cs +++ b/src/EFCore.Relational/Migrations/HistoryRepositoryDependencies.cs @@ -59,7 +59,8 @@ public HistoryRepositoryDependencies( IRelationalTypeMappingSource typeMappingSource, ICurrentDbContext currentContext, IModelRuntimeInitializer modelRuntimeInitializer, - IRelationalCommandDiagnosticsLogger commandLogger) + IRelationalCommandDiagnosticsLogger commandLogger, + IDiagnosticsLogger migrationsLogger) { DatabaseCreator = databaseCreator; RawSqlCommandBuilder = rawSqlCommandBuilder; @@ -75,6 +76,7 @@ public HistoryRepositoryDependencies( CurrentContext = currentContext; ModelRuntimeInitializer = modelRuntimeInitializer; CommandLogger = commandLogger; + MigrationsLogger = migrationsLogger; } /// @@ -146,4 +148,9 @@ public HistoryRepositoryDependencies( /// The command logger /// public IRelationalCommandDiagnosticsLogger CommandLogger { get; init; } + + /// + /// The migrations logger + /// + public IDiagnosticsLogger MigrationsLogger { get; init; } } diff --git a/src/EFCore.Relational/Migrations/IHistoryRepository.cs b/src/EFCore.Relational/Migrations/IHistoryRepository.cs index 7bf3a461650..2189e6cea87 100644 --- a/src/EFCore.Relational/Migrations/IHistoryRepository.cs +++ b/src/EFCore.Relational/Migrations/IHistoryRepository.cs @@ -50,12 +50,44 @@ public interface IHistoryRepository /// /// A to observe while waiting for the task to complete. /// - /// A task that represents the asynchronous operation. The task result contains - /// if the table already exists, otherwise. + /// A task that represents the asynchronous operation. /// /// If the is canceled. Task CreateAsync(CancellationToken cancellationToken = default); + /// + /// Creates the history table if it doesn't exist. + /// + /// if the table was created, otherwise. + bool CreateIfNotExists() + { + if (!Exists()) + { + Create(); + return true; + } + return false; + } + + /// + /// Creates the history table. + /// + /// A to observe while waiting for the task to complete. + /// + /// A task that represents the asynchronous operation. The task result contains + /// if the table was created, otherwise. + /// + /// If the is canceled. + async Task CreateIfNotExistsAsync(CancellationToken cancellationToken = default) + { + if (!await ExistsAsync(cancellationToken).ConfigureAwait(false)) + { + await CreateAsync(cancellationToken).ConfigureAwait(false); + return true; + } + return false; + } + /// /// Queries the history table for all migrations that have been applied. /// @@ -75,18 +107,23 @@ Task> GetAppliedMigrationsAsync( CancellationToken cancellationToken = default); /// - /// Gets an exclusive lock on the database. + /// The condition under witch the lock is released implicitly. + /// + LockReleaseBehavior LockReleaseBehavior { get; } + + /// + /// Acquires an exclusive lock on the database. /// /// An object that can be disposed to release the lock. - IDisposable GetDatabaseLock(); + IMigrationsDatabaseLock AcquireDatabaseLock(); /// - /// Gets an exclusive lock on the database. + /// Acquires an exclusive lock on the database asynchronously. /// /// A to observe while waiting for the task to complete. /// An object that can be disposed to release the lock. /// If the is canceled. - Task GetDatabaseLockAsync(CancellationToken cancellationToken = default); + Task AcquireDatabaseLockAsync(CancellationToken cancellationToken = default); /// /// Generates a SQL script that will create the history table. diff --git a/src/EFCore.Relational/Migrations/IMigrationCommandExecutor.cs b/src/EFCore.Relational/Migrations/IMigrationCommandExecutor.cs index 7069ba9c045..039bbaa4f15 100644 --- a/src/EFCore.Relational/Migrations/IMigrationCommandExecutor.cs +++ b/src/EFCore.Relational/Migrations/IMigrationCommandExecutor.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Data; + namespace Microsoft.EntityFrameworkCore.Migrations; /// @@ -28,6 +30,24 @@ void ExecuteNonQuery( IEnumerable migrationCommands, IRelationalConnection connection); + /// + /// Executes the given commands using the given database connection. + /// + /// The commands to execute. + /// The connection to use. + /// The state of the current migration execution. + /// + /// Indicates whether the transaction started by this call should be commited. + /// If , the transaction will be made available in . + /// + /// The isolation level for the transaction. + int ExecuteNonQuery( + IReadOnlyList migrationCommands, + IRelationalConnection connection, + MigrationExecutionState executionState, + bool commitTransaction, + IsolationLevel? isolationLevel = null); + /// /// Executes the given commands using the given database connection. /// @@ -40,4 +60,26 @@ Task ExecuteNonQueryAsync( IEnumerable migrationCommands, IRelationalConnection connection, CancellationToken cancellationToken = default); + + /// + /// Executes the given commands using the given database connection. + /// + /// The commands to execute. + /// The connection to use. + /// The state of the current migration execution. + /// + /// Indicates whether the transaction started by this call should be commited. + /// If , the transaction will be made available in . + /// + /// The isolation level for the transaction. + /// A to observe while waiting for the task to complete. + /// A task that represents the asynchronous operation. + /// If the is canceled. + Task ExecuteNonQueryAsync( + IReadOnlyList migrationCommands, + IRelationalConnection connection, + MigrationExecutionState executionState, + bool commitTransaction, + IsolationLevel? isolationLevel = null, + CancellationToken cancellationToken = default); } diff --git a/src/EFCore.Relational/Migrations/IMigrationsDatabaseLock.cs b/src/EFCore.Relational/Migrations/IMigrationsDatabaseLock.cs new file mode 100644 index 00000000000..b08ea1b9faa --- /dev/null +++ b/src/EFCore.Relational/Migrations/IMigrationsDatabaseLock.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Migrations; + +/// +/// Represents an exclusive lock on the database that is used to ensure that only one migration application can be run at a time. +/// +/// +/// Typically only database providers implement this. +/// +public interface IMigrationsDatabaseLock : IDisposable, IAsyncDisposable +{ + /// + /// The history repository. + /// + protected IHistoryRepository HistoryRepository { get; } + + /// + /// Acquires an exclusive lock on the database again if the current one was already released. + /// + /// Indicates whether the connection was reopened. + /// + /// Indicates whether the transaction was restarted. + /// if there's no current transaction. + /// + /// An object that can be disposed to release the lock. + IMigrationsDatabaseLock ReacquireIfNeeded(bool connectionReopened, bool? transactionRestarted) + { + if ((connectionReopened && HistoryRepository.LockReleaseBehavior == LockReleaseBehavior.Connection) + || (transactionRestarted is true && HistoryRepository.LockReleaseBehavior == LockReleaseBehavior.Transaction)) + { + Dispose(); + return HistoryRepository.AcquireDatabaseLock(); + } + + return this; + } + + /// + /// Acquires an exclusive lock on the database again, if the current one was already released. + /// + /// Indicates whether the connection was reopened. + /// + /// Indicates whether the transaction was restarted. + /// if there's no current transaction. + /// + /// A to observe while waiting for the task to complete. + /// An object that can be disposed to release the lock. + async Task ReacquireIfNeededAsync( + bool connectionReopened, bool? transactionRestarted, CancellationToken cancellationToken = default) + { + if ((connectionReopened && HistoryRepository.LockReleaseBehavior == LockReleaseBehavior.Connection) + || (transactionRestarted is true && HistoryRepository.LockReleaseBehavior == LockReleaseBehavior.Transaction)) + { + await DisposeAsync().ConfigureAwait(false); + return await HistoryRepository.AcquireDatabaseLockAsync(cancellationToken).ConfigureAwait(false); + } + + return this; + } +} diff --git a/src/EFCore.Relational/Migrations/Internal/MigrationCommandExecutor.cs b/src/EFCore.Relational/Migrations/Internal/MigrationCommandExecutor.cs index 4b2d78a85bc..68c6ba4a886 100644 --- a/src/EFCore.Relational/Migrations/Internal/MigrationCommandExecutor.cs +++ b/src/EFCore.Relational/Migrations/Internal/MigrationCommandExecutor.cs @@ -28,74 +28,120 @@ public class MigrationCommandExecutor(IExecutionStrategy executionStrategy) : IM public virtual void ExecuteNonQuery( IEnumerable migrationCommands, IRelationalConnection connection) + => ExecuteNonQuery( + migrationCommands.ToList(), connection, new MigrationExecutionState(), commitTransaction: true); + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual int ExecuteNonQuery( + IReadOnlyList migrationCommands, + IRelationalConnection connection, + MigrationExecutionState executionState, + bool commitTransaction, + System.Data.IsolationLevel? isolationLevel = null) { - // TODO: Remove ToList, see #19710 - var commands = migrationCommands.ToList(); - var userTransaction = connection.CurrentTransaction; - if (userTransaction is not null - && (commands.Any(x => x.TransactionSuppressed) || executionStrategy.RetriesOnFailure)) + var inUserTransaction = connection.CurrentTransaction is not null && executionState.Transaction == null; + if (inUserTransaction + && (migrationCommands.Any(x => x.TransactionSuppressed) || executionStrategy.RetriesOnFailure)) { throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction); } - using (new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled)) - { - var parameters = new ExecuteParameters(commands, connection); - if (userTransaction is null) - { - executionStrategy.Execute(parameters, static (_, p) => Execute(p, beginTransaction: true), verifySucceeded: null); - } - else - { - Execute(parameters, beginTransaction: false); - } - } + using var transactionScope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled); + + return executionStrategy.Execute( + (migrationCommands, connection, inUserTransaction, executionState, commitTransaction, isolationLevel), + static (_, s) => Execute( + s.migrationCommands, + s.connection, + s.executionState, + beginTransaction: !s.inUserTransaction, + commitTransaction: !s.inUserTransaction && s.commitTransaction, + s.isolationLevel), + verifySucceeded: null); } - private static bool Execute(ExecuteParameters parameters, bool beginTransaction) + private static int Execute( + IReadOnlyList migrationCommands, + IRelationalConnection connection, + MigrationExecutionState executionState, + bool beginTransaction, + bool commitTransaction, + System.Data.IsolationLevel? isolationLevel) { - var migrationCommands = parameters.MigrationCommands; - var connection = parameters.Connection; - IDbContextTransaction? transaction = null; - connection.Open(); + var result = 0; + var connectionOpened = connection.Open(); + Check.DebugAssert(!connectionOpened || executionState.Transaction == null, + "executionState.Transaction should be null"); + try { - for (var i = parameters.CurrentCommandIndex; i < migrationCommands.Count; i++) + for (var i = executionState.LastCommittedCommandIndex; i < migrationCommands.Count; i++) { var command = migrationCommands[i]; - if (transaction == null + if (executionState.Transaction == null && !command.TransactionSuppressed && beginTransaction) { - transaction = connection.BeginTransaction(); + executionState.Transaction = isolationLevel == null + ? connection.BeginTransaction() + : connection.BeginTransaction(isolationLevel.Value); + if (executionState.DatabaseLock != null) + { + executionState.DatabaseLock = executionState.DatabaseLock.ReacquireIfNeeded( + connectionOpened, transactionRestarted: true); + connectionOpened = false; + } } - if (transaction != null + if (executionState.Transaction != null && command.TransactionSuppressed) { - transaction.Commit(); - transaction.Dispose(); - transaction = null; - parameters.CurrentCommandIndex = i; + executionState.Transaction.Commit(); + executionState.Transaction.Dispose(); + executionState.Transaction = null; + executionState.LastCommittedCommandIndex = i; + executionState.AnyOperationPerformed = true; + + if (executionState.DatabaseLock != null) + { + executionState.DatabaseLock = executionState.DatabaseLock.ReacquireIfNeeded( + connectionOpened, transactionRestarted: null); + connectionOpened = false; + } } - command.ExecuteNonQuery(connection); + result = command.ExecuteNonQuery(connection); - if (transaction == null) + if (executionState.Transaction == null) { - parameters.CurrentCommandIndex = i + 1; + executionState.LastCommittedCommandIndex = i + 1; + executionState.AnyOperationPerformed = true; } } - transaction?.Commit(); + if (commitTransaction + && executionState.Transaction != null) + { + executionState.Transaction.Commit(); + executionState.Transaction.Dispose(); + executionState.Transaction = null; + } } - finally + catch { - transaction?.Dispose(); + executionState.Transaction?.Dispose(); + executionState.Transaction = null; connection.Close(); + throw; } - return true; + connection.Close(); + return result; } /// @@ -104,95 +150,136 @@ private static bool Execute(ExecuteParameters parameters, bool beginTransaction) /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual async Task ExecuteNonQueryAsync( + public virtual Task ExecuteNonQueryAsync( IEnumerable migrationCommands, IRelationalConnection connection, CancellationToken cancellationToken = default) + => ExecuteNonQueryAsync( + migrationCommands.ToList(), connection, new MigrationExecutionState(), commitTransaction: true, System.Data.IsolationLevel.Unspecified, cancellationToken); + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual async Task ExecuteNonQueryAsync( + IReadOnlyList migrationCommands, + IRelationalConnection connection, + MigrationExecutionState executionState, + bool commitTransaction, + System.Data.IsolationLevel? isolationLevel = null, + CancellationToken cancellationToken = default) { - var commands = migrationCommands.ToList(); - var userTransaction = connection.CurrentTransaction; - if (userTransaction is not null - && (commands.Any(x => x.TransactionSuppressed) || executionStrategy.RetriesOnFailure)) + var inUserTransaction = connection.CurrentTransaction is not null && executionState.Transaction == null; + if (inUserTransaction + && (migrationCommands.Any(x => x.TransactionSuppressed) || executionStrategy.RetriesOnFailure)) { throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction); } using var transactionScope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled); - var parameters = new ExecuteParameters(commands, connection); - if (userTransaction is null) - { - await executionStrategy.ExecuteAsync( - parameters, - static (_, p, ct) => ExecuteAsync(p, beginTransaction: true, ct), - verifySucceeded: null, - cancellationToken).ConfigureAwait(false); - } - else - { - await ExecuteAsync(parameters, beginTransaction: false, cancellationToken).ConfigureAwait(false); - } + return await executionStrategy.ExecuteAsync( + (migrationCommands, connection, inUserTransaction, executionState, commitTransaction, isolationLevel), + static (_, s, ct) => ExecuteAsync( + s.migrationCommands, + s.connection, + s.executionState, + beginTransaction: !s.inUserTransaction, + commitTransaction: !s.inUserTransaction && s.commitTransaction, + s.isolationLevel, + ct), + verifySucceeded: null, + cancellationToken).ConfigureAwait(false); } - private static async Task ExecuteAsync(ExecuteParameters parameters, bool beginTransaction, CancellationToken cancellationToken) + private static async Task ExecuteAsync( + IReadOnlyList migrationCommands, + IRelationalConnection connection, + MigrationExecutionState executionState, + bool beginTransaction, + bool commitTransaction, + System.Data.IsolationLevel? isolationLevel, + CancellationToken cancellationToken) { - var migrationCommands = parameters.MigrationCommands; - var connection = parameters.Connection; - IDbContextTransaction? transaction = null; - await connection.OpenAsync(cancellationToken).ConfigureAwait(false); + var result = 0; + var connectionOpened = await connection.OpenAsync(cancellationToken).ConfigureAwait(false); + Check.DebugAssert(!connectionOpened || executionState.Transaction == null, + "executionState.Transaction should be null"); + try { - for (var i = parameters.CurrentCommandIndex; i < migrationCommands.Count; i++) + for (var i = executionState.LastCommittedCommandIndex; i < migrationCommands.Count; i++) { + var lockReacquired = false; var command = migrationCommands[i]; - if (transaction == null + if (executionState.Transaction == null && !command.TransactionSuppressed && beginTransaction) { - transaction = await connection.BeginTransactionAsync(cancellationToken) + executionState.Transaction = await (isolationLevel == null + ? connection.BeginTransactionAsync(cancellationToken) + : connection.BeginTransactionAsync(isolationLevel.Value, cancellationToken)) .ConfigureAwait(false); + + if (executionState.DatabaseLock != null) + { + executionState.DatabaseLock = await executionState.DatabaseLock.ReacquireIfNeededAsync( + connectionOpened, transactionRestarted: true, cancellationToken) + .ConfigureAwait(false); + lockReacquired = true; + } } - if (transaction != null + if (executionState.Transaction != null && command.TransactionSuppressed) { - await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); - await transaction.DisposeAsync().ConfigureAwait(false); - transaction = null; - parameters.CurrentCommandIndex = i; + await executionState.Transaction.CommitAsync(cancellationToken).ConfigureAwait(false); + await executionState.Transaction.DisposeAsync().ConfigureAwait(false); + executionState.Transaction = null; + executionState.LastCommittedCommandIndex = i; + executionState.AnyOperationPerformed = true; + + if (executionState.DatabaseLock != null + && !lockReacquired) + { + executionState.DatabaseLock = await executionState.DatabaseLock.ReacquireIfNeededAsync( + connectionOpened, transactionRestarted: null, cancellationToken) + .ConfigureAwait(false); + } } - await command.ExecuteNonQueryAsync(connection, cancellationToken: cancellationToken) + result = await command.ExecuteNonQueryAsync(connection, cancellationToken: cancellationToken) .ConfigureAwait(false); - if (transaction == null) + if (executionState.Transaction == null) { - parameters.CurrentCommandIndex = i + 1; + executionState.LastCommittedCommandIndex = i + 1; + executionState.AnyOperationPerformed = true; } } - if (transaction != null) + if (commitTransaction + && executionState.Transaction != null) { - await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); + await executionState.Transaction.CommitAsync(cancellationToken).ConfigureAwait(false); + await executionState.Transaction.DisposeAsync().ConfigureAwait(false); + executionState.Transaction = null; } } - finally + catch { - if (transaction != null) + if (executionState.Transaction != null) { - await transaction.DisposeAsync().ConfigureAwait(false); + await executionState.Transaction.DisposeAsync().ConfigureAwait(false); + executionState.Transaction = null; } - await connection.CloseAsync().ConfigureAwait(false); + throw; } - return true; - } - - private sealed class ExecuteParameters(List migrationCommands, IRelationalConnection connection) - { - public int CurrentCommandIndex; - public List MigrationCommands { get; } = migrationCommands; - public IRelationalConnection Connection { get; } = connection; + await connection.CloseAsync().ConfigureAwait(false); + return result; } } diff --git a/src/EFCore.Relational/Migrations/Internal/Migrator.cs b/src/EFCore.Relational/Migrations/Internal/Migrator.cs index c10cdd105c0..a6644ef6fc1 100644 --- a/src/EFCore.Relational/Migrations/Internal/Migrator.cs +++ b/src/EFCore.Relational/Migrations/Internal/Migrator.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Transactions; using Microsoft.EntityFrameworkCore.Diagnostics.Internal; namespace Microsoft.EntityFrameworkCore.Migrations.Internal; @@ -29,6 +30,7 @@ public class Migrator : IMigrator private readonly IDesignTimeModel _designTimeModel; private readonly string _activeProvider; private readonly IDbContextOptions _contextOptions; + private readonly IExecutionStrategy _executionStrategy; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -52,7 +54,8 @@ public Migrator( IDatabaseProvider databaseProvider, IMigrationsModelDiffer migrationsModelDiffer, IDesignTimeModel designTimeModel, - IDbContextOptions contextOptions) + IDbContextOptions contextOptions, + IExecutionStrategy executionStrategy) { _migrationsAssembly = migrationsAssembly; _historyRepository = historyRepository; @@ -70,8 +73,17 @@ public Migrator( _designTimeModel = designTimeModel; _activeProvider = databaseProvider.Name; _contextOptions = contextOptions; + _executionStrategy = executionStrategy; } + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + protected virtual System.Data.IsolationLevel? MigrationTransactionIsolationLevel => null; + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -80,29 +92,90 @@ public Migrator( /// public virtual void Migrate(string? targetMigration) { + var useTransaction = _connection.CurrentTransaction is null; + if (!useTransaction + && _executionStrategy.RetriesOnFailure) + { + throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction); + } + if (RelationalResources.LogPendingModelChanges(_logger).WarningBehavior != WarningBehavior.Ignore && HasPendingModelChanges()) { _logger.PendingModelChangesWarning(_currentContext.Context.GetType()); } + if (!useTransaction) + { + _logger.MigrationsUserTransactionWarning(); + } + _logger.MigrateUsingConnection(this, _connection); + using var transactionScope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled); + if (!_databaseCreator.Exists()) { _databaseCreator.Create(); } + _connection.Open(); try { - _connection.Open(); + var state = new MigrationExecutionState(); + if (_historyRepository.LockReleaseBehavior != LockReleaseBehavior.Transaction + && useTransaction) + { + state.DatabaseLock = _historyRepository.AcquireDatabaseLock(); + } - _logger.AcquiringMigrationLock(); - using var _ = _historyRepository.GetDatabaseLock(); + _executionStrategy.Execute( + this, + static (_, migrator) => + { + migrator._connection.Open(); + try + { + return migrator._historyRepository.CreateIfNotExists(); + } + finally + { + migrator._connection.Close(); + } + }, + verifySucceeded: null); + + _executionStrategy.Execute( + (Migrator: this, + TargetMigration: targetMigration, + State: state, + UseTransaction: useTransaction), + static (c, s) => s.Migrator.MigrateImplementation(c, s.TargetMigration, s.State, s.UseTransaction), + static (_, s) => new ExecutionResult( + successful: s.Migrator.VerifyMigrationSucceeded(s.TargetMigration, s.State), + result: true)); + } + finally + { + _connection.Close(); + } + } - if (!_historyRepository.Exists()) + private bool MigrateImplementation( + DbContext context, string? targetMigration, MigrationExecutionState state, bool useTransaction) + { + var connectionOpened = _connection.Open(); + try + { + if (useTransaction) { - _historyRepository.Create(); + state.Transaction = MigrationTransactionIsolationLevel == null + ? _connection.BeginTransaction() + : _connection.BeginTransaction(MigrationTransactionIsolationLevel.Value); + + state.DatabaseLock = state.DatabaseLock == null + ? _historyRepository.AcquireDatabaseLock() + : state.DatabaseLock.ReacquireIfNeeded(connectionOpened, useTransaction); } PopulateMigrations( @@ -113,7 +186,15 @@ public virtual void Migrate(string? targetMigration) var commandLists = GetMigrationCommandLists(migratorData); foreach (var commandList in commandLists) { - _migrationCommandExecutor.ExecuteNonQuery(commandList(), _connection); + var (id, getCommands) = commandList; + if (id != state.CurrentMigrationId) + { + state.CurrentMigrationId = id; + state.LastCommittedCommandIndex = 0; + } + + _migrationCommandExecutor.ExecuteNonQuery( + getCommands(), _connection, state, commitTransaction: false, MigrationTransactionIsolationLevel); } var coreOptionsExtension = @@ -123,20 +204,22 @@ public virtual void Migrate(string? targetMigration) var seed = coreOptionsExtension.Seeder; if (seed != null) { - var context = _currentContext.Context; - var operationsPerformed = migratorData.AppliedMigrations.Count != 0 - || migratorData.RevertedMigrations.Count != 0; - using var transaction = context.Database.BeginTransaction(); - seed(context, operationsPerformed); - transaction.Commit(); + seed(context, state.AnyOperationPerformed); } else if (coreOptionsExtension.AsyncSeeder != null) { throw new InvalidOperationException(CoreStrings.MissingSeeder); } + + state.Transaction?.Commit(); + return state.AnyOperationPerformed; } finally { + state.DatabaseLock?.Dispose(); + state.DatabaseLock = null; + state.Transaction?.Dispose(); + state.Transaction = null; _connection.Close(); } } @@ -151,30 +234,96 @@ public virtual async Task MigrateAsync( string? targetMigration, CancellationToken cancellationToken = default) { + var useTransaction = _connection.CurrentTransaction is null; + if (!useTransaction + && _executionStrategy.RetriesOnFailure) + { + throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction); + } + if (RelationalResources.LogPendingModelChanges(_logger).WarningBehavior != WarningBehavior.Ignore && HasPendingModelChanges()) { _logger.PendingModelChangesWarning(_currentContext.Context.GetType()); } + if (!useTransaction) + { + _logger.MigrationsUserTransactionWarning(); + } + _logger.MigrateUsingConnection(this, _connection); + using var transactionScope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled); + if (!await _databaseCreator.ExistsAsync(cancellationToken).ConfigureAwait(false)) { await _databaseCreator.CreateAsync(cancellationToken).ConfigureAwait(false); } + await _connection.OpenAsync(cancellationToken).ConfigureAwait(false); try { - await _connection.OpenAsync(cancellationToken).ConfigureAwait(false); + var state = new MigrationExecutionState(); + if (_historyRepository.LockReleaseBehavior != LockReleaseBehavior.Transaction + && useTransaction) + { + state.DatabaseLock = await _historyRepository.AcquireDatabaseLockAsync(cancellationToken).ConfigureAwait(false); + } - _logger.AcquiringMigrationLock(); - var dbLock = await _historyRepository.GetDatabaseLockAsync(cancellationToken).ConfigureAwait(false); - await using var _ = dbLock.ConfigureAwait(false); + await _executionStrategy.ExecuteAsync( + this, + static async (_, migrator, ct) => + { + await migrator._connection.OpenAsync(ct).ConfigureAwait(false); + try + { + return await migrator._historyRepository.CreateIfNotExistsAsync(ct).ConfigureAwait(false); + } + finally + { + await migrator._connection.CloseAsync().ConfigureAwait(false); + } + }, + verifySucceeded: null, + cancellationToken).ConfigureAwait(false); + + await _executionStrategy.ExecuteAsync( + (Migrator: this, + TargetMigration: targetMigration, + State: state, + UseTransaction: useTransaction), + async static (c, s, ct) => await s.Migrator.MigrateImplementationAsync( + c, s.TargetMigration, s.State, s.UseTransaction, ct).ConfigureAwait(false), + async static (_, s, ct) => new ExecutionResult( + successful: await s.Migrator.VerifyMigrationSucceededAsync(s.TargetMigration, s.State, ct).ConfigureAwait(false), + result: true), + cancellationToken) + .ConfigureAwait(false); + } + finally + { + await _connection.CloseAsync().ConfigureAwait(false); + } + } - if (!await _historyRepository.ExistsAsync(cancellationToken).ConfigureAwait(false)) + private async Task MigrateImplementationAsync( + DbContext context, string? targetMigration, MigrationExecutionState state, bool useTransaction, CancellationToken cancellationToken = default) + { + var connectionOpened = await _connection.OpenAsync(cancellationToken).ConfigureAwait(false); + try + { + if (useTransaction) { - await _historyRepository.CreateAsync(cancellationToken).ConfigureAwait(false); + state.Transaction = await (MigrationTransactionIsolationLevel == null + ? context.Database.BeginTransactionAsync(cancellationToken) + : context.Database.BeginTransactionAsync(MigrationTransactionIsolationLevel.Value, cancellationToken)) + .ConfigureAwait(false); + + state.DatabaseLock = state.DatabaseLock == null + ? await _historyRepository.AcquireDatabaseLockAsync(cancellationToken).ConfigureAwait(false) + : await state.DatabaseLock.ReacquireIfNeededAsync(connectionOpened, useTransaction, cancellationToken) + .ConfigureAwait(false); } PopulateMigrations( @@ -185,7 +334,15 @@ public virtual async Task MigrateAsync( var commandLists = GetMigrationCommandLists(migratorData); foreach (var commandList in commandLists) { - await _migrationCommandExecutor.ExecuteNonQueryAsync(commandList(), _connection, cancellationToken) + var (id, getCommands) = commandList; + if (id != state.CurrentMigrationId) + { + state.CurrentMigrationId = id; + state.LastCommittedCommandIndex = 0; + } + + await _migrationCommandExecutor.ExecuteNonQueryAsync( + getCommands(), _connection, state, commitTransaction: false, MigrationTransactionIsolationLevel, cancellationToken) .ConfigureAwait(false); } @@ -196,26 +353,36 @@ await _migrationCommandExecutor.ExecuteNonQueryAsync(commandList(), _connection, var seedAsync = coreOptionsExtension.AsyncSeeder; if (seedAsync != null) { - var context = _currentContext.Context; - var operationsPerformed = migratorData.AppliedMigrations.Count != 0 - || migratorData.RevertedMigrations.Count != 0; - var transaction = await context.Database.BeginTransactionAsync(cancellationToken).ConfigureAwait(false); - await using var __ = transaction.ConfigureAwait(false); - await seedAsync(context, operationsPerformed, cancellationToken).ConfigureAwait(false); - await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); + await seedAsync(context, state.AnyOperationPerformed, cancellationToken).ConfigureAwait(false); } else if (coreOptionsExtension.Seeder != null) { throw new InvalidOperationException(CoreStrings.MissingSeeder); } + + if (state.Transaction != null) + { + await state.Transaction.CommitAsync(cancellationToken).ConfigureAwait(false); + } + return state.AnyOperationPerformed; } finally { - _connection.Close(); + if (state.DatabaseLock != null) + { + state.DatabaseLock.Dispose(); + state.DatabaseLock = null; + } + if (state.Transaction != null) + { + await state.Transaction.DisposeAsync().ConfigureAwait(false); + state.Transaction = null; + } + await _connection.CloseAsync().ConfigureAwait(false); } } - private IEnumerable>> GetMigrationCommandLists(MigratorData parameters) + private IEnumerable<(string, Func>)> GetMigrationCommandLists(MigratorData parameters) { var migrationsToApply = parameters.AppliedMigrations; var migrationsToRevert = parameters.RevertedMigrations; @@ -226,7 +393,7 @@ private IEnumerable>> GetMigrationCommandLi var migration = migrationsToRevert[i]; var index = i; - yield return () => + yield return (migration.GetId(), () => { _logger.MigrationReverting(this, migration); @@ -242,12 +409,12 @@ private IEnumerable>> GetMigrationCommandLi } return commands; - }; + }); } foreach (var migration in migrationsToApply) { - yield return () => + yield return (migration.GetId(), () => { _logger.MigrationApplying(this, migration); @@ -259,7 +426,7 @@ private IEnumerable>> GetMigrationCommandLi } return commands; - }; + }); } if (migrationsToRevert.Count + migrationsToApply.Count == 0) @@ -340,6 +507,26 @@ protected virtual void PopulateMigrations( parameters = new MigratorData(migrationsToApply, migrationsToRevert, actualTargetMigration); } + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + protected virtual bool VerifyMigrationSucceeded( + string? targetMigration, MigrationExecutionState state) + => false; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + protected virtual Task VerifyMigrationSucceededAsync( + string? targetMigration, MigrationExecutionState state, CancellationToken cancellationToken) + => Task.FromResult(false); + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in diff --git a/src/EFCore.Relational/Migrations/LockReleaseBehavior.cs b/src/EFCore.Relational/Migrations/LockReleaseBehavior.cs new file mode 100644 index 00000000000..bd1f96e995c --- /dev/null +++ b/src/EFCore.Relational/Migrations/LockReleaseBehavior.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Migrations; + +/// +/// Represents the conditions under which a lock is released implicitly. +/// +public enum LockReleaseBehavior +{ + /// + /// The lock is released when the transaction is committed or rolled back. + /// + Transaction, + + /// + /// The lock is released when the connection is closed. + /// + Connection, + + /// + /// The lock can only be released explicitly. + /// + Explicit +} diff --git a/src/EFCore.Relational/Migrations/MigrationExecutionState.cs b/src/EFCore.Relational/Migrations/MigrationExecutionState.cs new file mode 100644 index 00000000000..accd83e0cfc --- /dev/null +++ b/src/EFCore.Relational/Migrations/MigrationExecutionState.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Migrations; + +/// +/// Contains the state of the current migration execution. +/// +public sealed class MigrationExecutionState +{ + /// + /// The index of the last command that was committed to the database. + /// + public int LastCommittedCommandIndex { get; set; } + + /// + /// The id the migration that is currently being applied. + /// + public string? CurrentMigrationId { get; set; } + + /// + /// Indicates whether any migration operation was performed. + /// + public bool AnyOperationPerformed { get; set; } + + /// + /// The database lock that is in use. + /// + public IMigrationsDatabaseLock? DatabaseLock { get; set; } + + /// + /// The transaction that is in use. + /// + public IDbContextTransaction? Transaction { get; set; } +} diff --git a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs index c2350480259..731c62c4ec2 100644 --- a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs +++ b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs @@ -2130,7 +2130,7 @@ public static string UnsupportedOperatorForSqlExpression(object? nodeType, objec nodeType, expressionType); /// - /// No relational type mapping can be found for property '{entity}.{property}' and the current provider doesn't specify a default store type for the properties of type '{clrType}'. + /// No relational type mapping can be found for property '{entity}.{property}' and the current provider doesn't specify a default store type for the properties of type '{clrType}'. /// public static string UnsupportedPropertyType(object? entity, object? property, object? clrType) => string.Format( @@ -2256,7 +2256,7 @@ private static readonly ResourceManager _resourceManager = new ResourceManager("Microsoft.EntityFrameworkCore.Properties.RelationalStrings", typeof(RelationalResources).Assembly); /// - /// Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations for more information if this takes too long. + /// Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long. /// public static EventDefinition LogAcquiringMigrationLock(IDiagnosticsLogger logger) { @@ -3424,6 +3424,31 @@ public static EventDefinition LogMigrationAttributeMissingWarning(IDiagn return (EventDefinition)definition; } + /// + /// A transaction was started before applying migrations. This prevents a database lock to be acquired and hence the database will not be protected from concurrent migration applications. The transactions and execution strategy are already managed by EF as needed. Remove the external transaction. + /// + public static EventDefinition LogMigrationsUserTransaction(IDiagnosticsLogger logger) + { + var definition = ((RelationalLoggingDefinitions)logger.Definitions).LogMigrationsUserTransactionWarning; + if (definition == null) + { + definition = NonCapturingLazyInitializer.EnsureInitialized( + ref ((RelationalLoggingDefinitions)logger.Definitions).LogMigrationsUserTransactionWarning, + logger, + static logger => new EventDefinition( + logger.Options, + RelationalEventId.MigrationsUserTransactionWarning, + LogLevel.Warning, + "RelationalEventId.MigrationsUserTransactionWarning", + level => LoggerMessage.Define( + level, + RelationalEventId.MigrationsUserTransactionWarning, + _resourceManager.GetString("LogMigrationsUserTransaction")!))); + } + + return (EventDefinition)definition; + } + /// /// Compiling a query which loads related collections for more than one collection navigation, either via 'Include' or through projection, but no 'QuerySplittingBehavior' has been configured. By default, Entity Framework will use 'QuerySplittingBehavior.SingleQuery', which can potentially result in slow query performance. See https://go.microsoft.com/fwlink/?linkid=2134277 for more information. To identify the query that's triggering this warning call 'ConfigureWarnings(w => w.Throw(RelationalEventId.MultipleCollectionIncludeWarning))'. /// diff --git a/src/EFCore.Relational/Properties/RelationalStrings.resx b/src/EFCore.Relational/Properties/RelationalStrings.resx index d6390b417fc..104daf9dafb 100644 --- a/src/EFCore.Relational/Properties/RelationalStrings.resx +++ b/src/EFCore.Relational/Properties/RelationalStrings.resx @@ -1,17 +1,17 @@  - @@ -786,6 +786,10 @@ A [Migration] attribute isn't specified on the '{class}' class. Warning RelationalEventId.MigrationAttributeMissingWarning string + + A transaction was started before applying migrations. This prevents a database lock to be acquired and hence the database will not be protected from concurrent migration applications. The transactions and execution strategy are already managed by EF as needed. Remove the external transaction. + Warning RelationalEventId.MigrationsUserTransactionWarning + Compiling a query which loads related collections for more than one collection navigation, either via 'Include' or through projection, but no 'QuerySplittingBehavior' has been configured. By default, Entity Framework will use 'QuerySplittingBehavior.SingleQuery', which can potentially result in slow query performance. See https://go.microsoft.com/fwlink/?linkid=2134277 for more information. To identify the query that's triggering this warning call 'ConfigureWarnings(w => w.Throw(RelationalEventId.MultipleCollectionIncludeWarning))'. Warning RelationalEventId.MultipleCollectionIncludeWarning diff --git a/src/EFCore.Relational/Storage/RelationalDatabaseCreator.cs b/src/EFCore.Relational/Storage/RelationalDatabaseCreator.cs index ad6a2bcd7df..96f5ca0f76a 100644 --- a/src/EFCore.Relational/Storage/RelationalDatabaseCreator.cs +++ b/src/EFCore.Relational/Storage/RelationalDatabaseCreator.cs @@ -116,7 +116,7 @@ public virtual Task DeleteAsync(CancellationToken cancellationToken = default) /// to incrementally update the schema. It is assumed that none of the tables exist in the database. /// public virtual void CreateTables() - => Dependencies.MigrationCommandExecutor.ExecuteNonQuery(GetCreateTablesCommands(), Dependencies.Connection); + => Dependencies.MigrationCommandExecutor.ExecuteNonQuery(GetCreateTablesCommands(), Dependencies.Connection, new MigrationExecutionState(), commitTransaction: true); /// /// Asynchronously creates all tables for the current model in the database. No attempt is made @@ -129,7 +129,7 @@ public virtual void CreateTables() /// If the is canceled. public virtual Task CreateTablesAsync(CancellationToken cancellationToken = default) => Dependencies.MigrationCommandExecutor.ExecuteNonQueryAsync( - GetCreateTablesCommands(), Dependencies.Connection, cancellationToken); + GetCreateTablesCommands(), Dependencies.Connection, new MigrationExecutionState(), commitTransaction: true, cancellationToken: cancellationToken); /// /// Gets the commands that will create all tables from the model. diff --git a/src/EFCore.SqlServer/Migrations/Internal/SqlServerHistoryRepository.cs b/src/EFCore.SqlServer/Migrations/Internal/SqlServerHistoryRepository.cs index cc22d67fca4..202c7a2c131 100644 --- a/src/EFCore.SqlServer/Migrations/Internal/SqlServerHistoryRepository.cs +++ b/src/EFCore.SqlServer/Migrations/Internal/SqlServerHistoryRepository.cs @@ -59,8 +59,18 @@ protected override bool InterpretExistsResult(object? value) /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override IDisposable GetDatabaseLock() + public override LockReleaseBehavior LockReleaseBehavior => LockReleaseBehavior.Connection; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public override IMigrationsDatabaseLock AcquireDatabaseLock() { + Dependencies.MigrationsLogger.AcquiringMigrationLock(); + var dbLock = CreateMigrationDatabaseLock(); int result; try @@ -91,8 +101,10 @@ public override IDisposable GetDatabaseLock() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override async Task GetDatabaseLockAsync(CancellationToken cancellationToken = default) + public override async Task AcquireDatabaseLockAsync(CancellationToken cancellationToken = default) { + Dependencies.MigrationsLogger.AcquiringMigrationLock(); + var dbLock = CreateMigrationDatabaseLock(); int result; try @@ -135,7 +147,8 @@ private SqlServerMigrationDatabaseLock CreateMigrationDatabaseLock() EXEC @result = sp_releaseapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session'; SELECT @result """), - CreateRelationalCommandParameters()); + CreateRelationalCommandParameters(), + this); private RelationalCommandParameterObject CreateRelationalCommandParameters() => new( diff --git a/src/EFCore.SqlServer/Migrations/Internal/SqlServerMigrationDatabaseLock.cs b/src/EFCore.SqlServer/Migrations/Internal/SqlServerMigrationDatabaseLock.cs index c102f6f9705..b31ff900625 100644 --- a/src/EFCore.SqlServer/Migrations/Internal/SqlServerMigrationDatabaseLock.cs +++ b/src/EFCore.SqlServer/Migrations/Internal/SqlServerMigrationDatabaseLock.cs @@ -16,11 +16,20 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Migrations.Internal; /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public class SqlServerMigrationDatabaseLock( - IRelationalCommand relationalCommand, + IRelationalCommand releaseLockCommand, RelationalCommandParameterObject relationalCommandParameters, + IHistoryRepository historyRepository, CancellationToken cancellationToken = default) - : IDisposable, IAsyncDisposable + : IMigrationsDatabaseLock { + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual IHistoryRepository HistoryRepository => historyRepository; + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -28,7 +37,7 @@ public class SqlServerMigrationDatabaseLock( /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public void Dispose() - => relationalCommand.ExecuteScalar(relationalCommandParameters); + => releaseLockCommand.ExecuteScalar(relationalCommandParameters); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -37,5 +46,5 @@ public void Dispose() /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public async ValueTask DisposeAsync() - => await relationalCommand.ExecuteScalarAsync(relationalCommandParameters, cancellationToken).ConfigureAwait(false); + => await releaseLockCommand.ExecuteScalarAsync(relationalCommandParameters, cancellationToken).ConfigureAwait(false); } diff --git a/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs b/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs index 589440790a1..e3f3fcdb838 100644 --- a/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs +++ b/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs @@ -14,26 +14,19 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal; /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// -public class SqlServerDatabaseCreator : RelationalDatabaseCreator +/// +/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to +/// the same compatibility standards as public APIs. It may be changed or removed without notice in +/// any release. You should only use it directly in your code with extreme caution and knowing that +/// doing so can result in application failures when updating to a new Entity Framework Core release. +/// +public class SqlServerDatabaseCreator( + RelationalDatabaseCreatorDependencies dependencies, + ISqlServerConnection connection, + IRawSqlCommandBuilder rawSqlCommandBuilder) : RelationalDatabaseCreator(dependencies) { - private readonly ISqlServerConnection _connection; - private readonly IRawSqlCommandBuilder _rawSqlCommandBuilder; - - /// - /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to - /// the same compatibility standards as public APIs. It may be changed or removed without notice in - /// any release. You should only use it directly in your code with extreme caution and knowing that - /// doing so can result in application failures when updating to a new Entity Framework Core release. - /// - public SqlServerDatabaseCreator( - RelationalDatabaseCreatorDependencies dependencies, - ISqlServerConnection connection, - IRawSqlCommandBuilder rawSqlCommandBuilder) - : base(dependencies) - { - _connection = connection; - _rawSqlCommandBuilder = rawSqlCommandBuilder; - } + private readonly ISqlServerConnection _connection = connection; + private readonly IRawSqlCommandBuilder _rawSqlCommandBuilder = rawSqlCommandBuilder; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -62,7 +55,7 @@ public override void Create() using (var masterConnection = _connection.CreateMasterConnection()) { Dependencies.MigrationCommandExecutor - .ExecuteNonQuery(CreateCreateOperations(), masterConnection); + .ExecuteNonQuery(CreateCreateOperations(), masterConnection, new MigrationExecutionState(), commitTransaction: true); ClearPool(); } @@ -82,7 +75,7 @@ public override async Task CreateAsync(CancellationToken cancellationToken = def await using (masterConnection.ConfigureAwait(false)) { await Dependencies.MigrationCommandExecutor - .ExecuteNonQueryAsync(CreateCreateOperations(), masterConnection, cancellationToken) + .ExecuteNonQueryAsync(CreateCreateOperations(), masterConnection, new MigrationExecutionState(), commitTransaction: true, cancellationToken: cancellationToken) .ConfigureAwait(false); ClearPool(); @@ -157,8 +150,7 @@ private IReadOnlyList CreateCreateOperations() { var builder = new SqlConnectionStringBuilder(_connection.DbConnection.ConnectionString); return Dependencies.MigrationsSqlGenerator.Generate( - new[] - { + [ new SqlServerCreateDatabaseOperation { Name = builder.InitialCatalog, @@ -166,7 +158,7 @@ private IReadOnlyList CreateCreateOperations() Collation = Dependencies.CurrentContext.Context.GetService() .Model.GetRelationalModel().Collation } - }); + ]); } /// @@ -345,7 +337,7 @@ public override void Delete() using var masterConnection = _connection.CreateMasterConnection(); Dependencies.MigrationCommandExecutor - .ExecuteNonQuery(CreateDropCommands(), masterConnection); + .ExecuteNonQuery(CreateDropCommands(), masterConnection, new MigrationExecutionState(), commitTransaction: true); } /// @@ -361,7 +353,7 @@ public override async Task DeleteAsync(CancellationToken cancellationToken = def var masterConnection = _connection.CreateMasterConnection(); await using var _ = masterConnection.ConfigureAwait(false); await Dependencies.MigrationCommandExecutor - .ExecuteNonQueryAsync(CreateDropCommands(), masterConnection, cancellationToken) + .ExecuteNonQueryAsync(CreateDropCommands(), masterConnection, new MigrationExecutionState(), commitTransaction: true, cancellationToken: cancellationToken) .ConfigureAwait(false); } diff --git a/src/EFCore.Sqlite.Core/Migrations/Internal/SqliteHistoryRepository.cs b/src/EFCore.Sqlite.Core/Migrations/Internal/SqliteHistoryRepository.cs index e346fd1e698..89d8fefc0c8 100644 --- a/src/EFCore.Sqlite.Core/Migrations/Internal/SqliteHistoryRepository.cs +++ b/src/EFCore.Sqlite.Core/Migrations/Internal/SqliteHistoryRepository.cs @@ -103,11 +103,21 @@ public override string GetEndIfScript() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override IDisposable GetDatabaseLock() + public override LockReleaseBehavior LockReleaseBehavior => LockReleaseBehavior.Explicit; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public override IMigrationsDatabaseLock AcquireDatabaseLock() { + Dependencies.MigrationsLogger.AcquiringMigrationLock(); + if (!InterpretExistsResult( - Dependencies.RawSqlCommandBuilder.Build(CreateExistsSql(LockTableName)) - .ExecuteScalar(CreateRelationalCommandParameters()))) + Dependencies.RawSqlCommandBuilder.Build(CreateExistsSql(LockTableName)) + .ExecuteScalar(CreateRelationalCommandParameters()))) { CreateLockTableCommand().ExecuteNonQuery(CreateRelationalCommandParameters()); } @@ -129,8 +139,6 @@ public override IDisposable GetDatabaseLock() retryDelay = retryDelay.Add(retryDelay); } } - - throw new TimeoutException(); } /// @@ -139,11 +147,14 @@ public override IDisposable GetDatabaseLock() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override async Task GetDatabaseLockAsync(CancellationToken cancellationToken = default) + public override async Task AcquireDatabaseLockAsync( + CancellationToken cancellationToken = default) { + Dependencies.MigrationsLogger.AcquiringMigrationLock(); + if (!InterpretExistsResult( - await Dependencies.RawSqlCommandBuilder.Build(CreateExistsSql(LockTableName)) - .ExecuteScalarAsync(CreateRelationalCommandParameters(), cancellationToken).ConfigureAwait(false))) + await Dependencies.RawSqlCommandBuilder.Build(CreateExistsSql(LockTableName)) + .ExecuteScalarAsync(CreateRelationalCommandParameters(), cancellationToken).ConfigureAwait(false))) { await CreateLockTableCommand().ExecuteNonQueryAsync(CreateRelationalCommandParameters(), cancellationToken) .ConfigureAwait(false); @@ -167,8 +178,6 @@ await CreateLockTableCommand().ExecuteNonQueryAsync(CreateRelationalCommandParam retryDelay = retryDelay.Add(retryDelay); } } - - throw new TimeoutException(); } private IRelationalCommand CreateLockTableCommand() @@ -206,7 +215,7 @@ DELETE FROM "{LockTableName}" } private SqliteMigrationDatabaseLock CreateMigrationDatabaseLock() - => new(CreateDeleteLockCommand(), CreateRelationalCommandParameters()); + => new(CreateDeleteLockCommand(), CreateRelationalCommandParameters(), this); private RelationalCommandParameterObject CreateRelationalCommandParameters() => new( diff --git a/src/EFCore.Sqlite.Core/Migrations/Internal/SqliteMigrationDatabaseLock.cs b/src/EFCore.Sqlite.Core/Migrations/Internal/SqliteMigrationDatabaseLock.cs index 997cbcd4710..668d2107eaf 100644 --- a/src/EFCore.Sqlite.Core/Migrations/Internal/SqliteMigrationDatabaseLock.cs +++ b/src/EFCore.Sqlite.Core/Migrations/Internal/SqliteMigrationDatabaseLock.cs @@ -10,11 +10,20 @@ namespace Microsoft.EntityFrameworkCore.Sqlite.Migrations.Internal; /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public class SqliteMigrationDatabaseLock( - IRelationalCommand relationalCommand, + IRelationalCommand releaseLockCommand, RelationalCommandParameterObject relationalCommandParameters, + IHistoryRepository historyRepository, CancellationToken cancellationToken = default) - : IDisposable, IAsyncDisposable + : IMigrationsDatabaseLock { + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual IHistoryRepository HistoryRepository => historyRepository; + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -22,7 +31,7 @@ public class SqliteMigrationDatabaseLock( /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public void Dispose() - => relationalCommand.ExecuteScalar(relationalCommandParameters); + => releaseLockCommand.ExecuteScalar(relationalCommandParameters); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -31,5 +40,5 @@ public void Dispose() /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public async ValueTask DisposeAsync() - => await relationalCommand.ExecuteScalarAsync(relationalCommandParameters, cancellationToken).ConfigureAwait(false); + => await releaseLockCommand.ExecuteScalarAsync(relationalCommandParameters, cancellationToken).ConfigureAwait(false); } diff --git a/test/EFCore.Design.Tests/Design/DesignTimeServicesTest.cs b/test/EFCore.Design.Tests/Design/DesignTimeServicesTest.cs index c2c58289d54..ee13f8d8c34 100644 --- a/test/EFCore.Design.Tests/Design/DesignTimeServicesTest.cs +++ b/test/EFCore.Design.Tests/Design/DesignTimeServicesTest.cs @@ -192,6 +192,8 @@ public bool IsValidId(string value) public class ExtensionHistoryRepository : IHistoryRepository { + public virtual LockReleaseBehavior LockReleaseBehavior => LockReleaseBehavior.Explicit; + public void Create() => throw new NotImplementedException(); @@ -222,10 +224,10 @@ public string GetCreateIfNotExistsScript() public string GetCreateScript() => throw new NotImplementedException(); - public IDisposable GetDatabaseLock() + public IMigrationsDatabaseLock AcquireDatabaseLock() => throw new NotImplementedException(); - public Task GetDatabaseLockAsync(CancellationToken cancellationToken = default) + public Task AcquireDatabaseLockAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); public string GetDeleteScript(string migrationId) @@ -264,6 +266,8 @@ public bool IsValidId(string value) public class ContextHistoryRepository : IHistoryRepository { + public virtual LockReleaseBehavior LockReleaseBehavior => LockReleaseBehavior.Explicit; + public bool Exists() => throw new NotImplementedException(); @@ -294,10 +298,10 @@ public void Create() public Task CreateAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); - public IDisposable GetDatabaseLock() + public IMigrationsDatabaseLock AcquireDatabaseLock() => throw new NotImplementedException(); - public Task GetDatabaseLockAsync(CancellationToken cancellationToken = default) + public Task AcquireDatabaseLockAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); public string GetDeleteScript(string migrationId) diff --git a/test/EFCore.Design.Tests/Migrations/Design/MigrationScaffolderTest.cs b/test/EFCore.Design.Tests/Migrations/Design/MigrationScaffolderTest.cs index 94fa478789e..45f138e904b 100644 --- a/test/EFCore.Design.Tests/Migrations/Design/MigrationScaffolderTest.cs +++ b/test/EFCore.Design.Tests/Migrations/Design/MigrationScaffolderTest.cs @@ -125,7 +125,8 @@ var migrationAssembly services.GetRequiredService(), services.GetRequiredService(), services.GetRequiredService(), - services.GetRequiredService()))); + services.GetRequiredService(), + services.GetRequiredService()))); } // ReSharper disable once UnusedTypeParameter @@ -143,6 +144,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) private class MockHistoryRepository : IHistoryRepository { + public virtual LockReleaseBehavior LockReleaseBehavior => LockReleaseBehavior.Explicit; + public string GetBeginIfExistsScript(string migrationId) => null; @@ -182,10 +185,10 @@ public void Create() public Task CreateAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); - public IDisposable GetDatabaseLock() + public IMigrationsDatabaseLock AcquireDatabaseLock() => throw new NotImplementedException(); - public Task GetDatabaseLockAsync(CancellationToken cancellationToken = default) + public Task AcquireDatabaseLockAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); } diff --git a/test/EFCore.Relational.Tests/Extensions/RelationalDatabaseFacadeExtensionsTest.cs b/test/EFCore.Relational.Tests/Extensions/RelationalDatabaseFacadeExtensionsTest.cs index 3e56284521a..f2d2a935de3 100644 --- a/test/EFCore.Relational.Tests/Extensions/RelationalDatabaseFacadeExtensionsTest.cs +++ b/test/EFCore.Relational.Tests/Extensions/RelationalDatabaseFacadeExtensionsTest.cs @@ -321,6 +321,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) private class FakeHistoryRepository : IHistoryRepository { + public virtual LockReleaseBehavior LockReleaseBehavior => LockReleaseBehavior.Explicit; + public List AppliedMigrations { get; set; } public IReadOnlyList GetAppliedMigrations() @@ -362,10 +364,10 @@ public void Create() public Task CreateAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); - public IDisposable GetDatabaseLock() + public IMigrationsDatabaseLock AcquireDatabaseLock() => throw new NotImplementedException(); - public Task GetDatabaseLockAsync(CancellationToken cancellationToken = default) + public Task AcquireDatabaseLockAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs index 8aeb88a4e31..3d1c63e96ef 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs @@ -1017,13 +1017,16 @@ SELECT 1 EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; SELECT @result -SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; -CREATE TABLE [__EFMigrationsHistory] ( - [MigrationId] nvarchar(150) NOT NULL, - [ProductVersion] nvarchar(32) NOT NULL, - CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) -); +SELECT 1 SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); @@ -1047,6 +1050,22 @@ CONSTRAINT [PK_Blogs] PRIMARY KEY ([Id]) THROW 65536, 'Test', 0; END +DECLARE @result int; +EXEC @result = sp_releaseapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session'; +SELECT @result + +DECLARE @result int; +EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; +SELECT @result + +SELECT 1 + +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); + +SELECT [MigrationId], [ProductVersion] +FROM [__EFMigrationsHistory] +ORDER BY [MigrationId]; + IF OBJECT_ID(N'Blogs', N'U') IS NULL BEGIN CREATE TABLE [Blogs] ( @@ -1110,13 +1129,16 @@ SELECT 1 EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; SELECT @result -SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; -CREATE TABLE [__EFMigrationsHistory] ( - [MigrationId] nvarchar(150) NOT NULL, - [ProductVersion] nvarchar(32) NOT NULL, - CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) -); +SELECT 1 SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); @@ -1140,6 +1162,22 @@ CONSTRAINT [PK_Blogs] PRIMARY KEY ([Id]) THROW 65536, 'Test', 0; END +DECLARE @result int; +EXEC @result = sp_releaseapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session'; +SELECT @result + +DECLARE @result int; +EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; +SELECT @result + +SELECT 1 + +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); + +SELECT [MigrationId], [ProductVersion] +FROM [__EFMigrationsHistory] +ORDER BY [MigrationId]; + IF OBJECT_ID(N'Blogs', N'U') IS NULL BEGIN CREATE TABLE [Blogs] ( @@ -2078,7 +2116,8 @@ IF EXISTS(select * from sys.databases where name='TransactionSuppressed') public override MigrationsContext CreateContext() { var options = AddOptions(TestStore.AddProviderOptions(new DbContextOptionsBuilder())) - .UseSqlServer(TestStore.ConnectionString, b => b.ApplyConfiguration()) + .UseSqlServer(TestStore.ConnectionString, b => b + .ApplyConfiguration()) .UseInternalServiceProvider(ServiceProvider) .Options; return new MigrationsContext(options); diff --git a/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestSqlServerRetryingExecutionStrategy.cs b/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestSqlServerRetryingExecutionStrategy.cs index ec517ff802f..ac0eea2e54c 100644 --- a/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestSqlServerRetryingExecutionStrategy.cs +++ b/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestSqlServerRetryingExecutionStrategy.cs @@ -43,6 +43,13 @@ public TestSqlServerRetryingExecutionStrategy(ExecutionStrategyDependencies depe { } + public TestSqlServerRetryingExecutionStrategy( + ExecutionStrategyDependencies dependencies, + IEnumerable errorNumbersToAdd) + : base(dependencies, DefaultMaxRetryCount, DefaultMaxDelay, _additionalErrorNumbers.Concat(errorNumbersToAdd)) + { + } + protected override bool ShouldRetryOn(Exception exception) { if (base.ShouldRetryOn(exception)) From b2e366bf1d1955903c75c06288bad5bc5b8deda0 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Tue, 3 Sep 2024 13:44:59 -0700 Subject: [PATCH 29/32] [release/8.0] Update FK ElementType when the FK properties change. (#34561) Fixes #33704 --- .../Internal/CosmosTypeMappingSource.cs | 24 +++++ .../ElementTypeChangedConvention.cs | 23 ++++- .../Internal/InternalPropertyBuilder.cs | 8 ++ .../CosmosModelBuilderGenericTest.cs | 94 +++++++++---------- .../ModelBuilding/OwnedTypesTestBase.cs | 45 +++++++-- test/EFCore.Tests/ModelBuilding/TestModel.cs | 6 +- 6 files changed, 144 insertions(+), 56 deletions(-) diff --git a/src/EFCore.Cosmos/Storage/Internal/CosmosTypeMappingSource.cs b/src/EFCore.Cosmos/Storage/Internal/CosmosTypeMappingSource.cs index 8f7cc37bd56..78dd77f4f3a 100644 --- a/src/EFCore.Cosmos/Storage/Internal/CosmosTypeMappingSource.cs +++ b/src/EFCore.Cosmos/Storage/Internal/CosmosTypeMappingSource.cs @@ -3,6 +3,7 @@ using System.Collections.ObjectModel; using Microsoft.EntityFrameworkCore.Cosmos.ChangeTracking.Internal; +using Microsoft.EntityFrameworkCore.Storage.Json; using Newtonsoft.Json.Linq; namespace Microsoft.EntityFrameworkCore.Cosmos.Storage.Internal; @@ -17,6 +18,9 @@ public class CosmosTypeMappingSource : TypeMappingSource { private readonly Dictionary _clrTypeMappings; + internal static readonly bool UseOldBehavior33704 = + AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue33704", out var enabled33704) && enabled33704; + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -69,6 +73,26 @@ public CosmosTypeMappingSource(TypeMappingSourceDependencies dependencies) return null; } + /// + protected override bool TryFindJsonCollectionMapping( + TypeMappingInfo mappingInfo, + Type modelClrType, + Type? providerClrType, + ref CoreTypeMapping? elementMapping, + out ValueComparer? elementComparer, + out JsonValueReaderWriter? collectionReaderWriter) + { + if (UseOldBehavior33704) + { + return base.TryFindJsonCollectionMapping( + mappingInfo, modelClrType, providerClrType, ref elementMapping, out elementComparer, out collectionReaderWriter); + } + + elementComparer = null; + collectionReaderWriter = null; + return false; + } + private CoreTypeMapping? FindCollectionMapping(in TypeMappingInfo mappingInfo) { var clrType = mappingInfo.ClrType!; diff --git a/src/EFCore/Metadata/Conventions/ElementTypeChangedConvention.cs b/src/EFCore/Metadata/Conventions/ElementTypeChangedConvention.cs index 3e40ea9269e..7f1f12b35a5 100644 --- a/src/EFCore/Metadata/Conventions/ElementTypeChangedConvention.cs +++ b/src/EFCore/Metadata/Conventions/ElementTypeChangedConvention.cs @@ -9,11 +9,15 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; /// /// See Model building conventions for more information and examples. /// -public class ElementTypeChangedConvention : IPropertyElementTypeChangedConvention, IForeignKeyAddedConvention +public class ElementTypeChangedConvention : + IPropertyElementTypeChangedConvention, IForeignKeyAddedConvention, IForeignKeyPropertiesChangedConvention { internal static readonly bool UseOldBehavior32411 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32411", out var enabled32411) && enabled32411; + internal static readonly bool UseOldBehavior33704 = + AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue33704", out var enabled33704) && enabled33704; + /// /// Creates a new instance of . /// @@ -50,6 +54,23 @@ public void ProcessPropertyElementTypeChanged( /// public void ProcessForeignKeyAdded( IConventionForeignKeyBuilder foreignKeyBuilder, IConventionContext context) + => ProcessForeignKey(foreignKeyBuilder); + + /// + public void ProcessForeignKeyPropertiesChanged( + IConventionForeignKeyBuilder relationshipBuilder, + IReadOnlyList oldDependentProperties, + IConventionKey oldPrincipalKey, + IConventionContext> context) + { + if (relationshipBuilder.Metadata.IsInModel + && !UseOldBehavior33704) + { + ProcessForeignKey(relationshipBuilder); + } + } + + private static void ProcessForeignKey(IConventionForeignKeyBuilder foreignKeyBuilder) { var foreignKeyProperties = foreignKeyBuilder.Metadata.Properties; var principalKeyProperties = foreignKeyBuilder.Metadata.PrincipalKey.Properties; diff --git a/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs b/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs index 63443cb2bef..e3e43e88dff 100644 --- a/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs @@ -802,6 +802,14 @@ public virtual bool CanSetProviderValueComparer( { Metadata.SetValueConverter((Type?)null, configurationSource); } + + if (elementType == null + && CanSetConversion((Type?)null, configurationSource) + && !ElementTypeChangedConvention.UseOldBehavior33704) + { + Metadata.RemoveAnnotation(CoreAnnotationNames.ValueConverter); + } + return new InternalElementTypeBuilder(Metadata.GetElementType()!, ModelBuilder); } diff --git a/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs b/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs index a528c3d2df6..4a1fd8ecb06 100644 --- a/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs +++ b/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs @@ -13,181 +13,181 @@ public class CosmosGenericNonRelationship : GenericNonRelationship { public override void Can_set_composite_key_for_primitive_collection_on_an_entity_with_fields() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(EntityWithFields), "CollectionCompanyId"), + CoreStrings.PropertyNotMapped("int[]", nameof(EntityWithFields), "CollectionCompanyId"), Assert.Throws( () => base.Can_set_composite_key_for_primitive_collection_on_an_entity_with_fields()).Message); public override void Access_mode_can_be_overridden_at_entity_and_primitive_collection_levels() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Down"), + CoreStrings.PropertyNotMapped("ObservableCollection", nameof(CollectionQuarks), "Down"), Assert.Throws( () => base.Access_mode_can_be_overridden_at_entity_and_primitive_collection_levels()).Message); public override void Can_set_custom_value_generator_for_primitive_collections() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Bottom"), Assert.Throws( () => base.Can_set_custom_value_generator_for_primitive_collections()).Message); public override void Can_set_element_type_annotation() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(Customer), "Notes"), + CoreStrings.PropertyNotMapped("List", nameof(Customer), "Notes"), Assert.Throws( () => base.Can_set_element_type_annotation()).Message); public override void Can_set_max_length_for_primitive_collections() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), + CoreStrings.PropertyNotMapped("string[]", nameof(CollectionQuarks), "Bottom"), Assert.Throws( () => base.Can_set_max_length_for_primitive_collections()).Message); public override void Can_set_primitive_collection_annotation() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(Customer), "Notes"), + CoreStrings.PropertyNotMapped("List", nameof(Customer), "Notes"), Assert.Throws( () => base.Can_set_primitive_collection_annotation()).Message); public override void Can_set_primitive_collection_annotation_by_type() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(Customer), "Notes"), + CoreStrings.PropertyNotMapped("List", nameof(Customer), "Notes"), Assert.Throws( () => base.Can_set_primitive_collection_annotation_by_type()).Message); public override void Can_set_primitive_collection_annotation_when_no_clr_property() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(Customer), "Notes"), + CoreStrings.PropertyNotMapped("List", nameof(Customer), "Notes"), Assert.Throws( () => base.Can_set_primitive_collection_annotation_when_no_clr_property()).Message); public override void Can_set_sentinel_for_primitive_collections() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Bottom"), Assert.Throws( () => base.Can_set_sentinel_for_primitive_collections()).Message); public override void Can_set_unicode_for_primitive_collections() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Bottom"), Assert.Throws( () => base.Can_set_unicode_for_primitive_collections()).Message); public override void Element_types_are_nullable_by_default_if_the_type_is_nullable() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Element_types_are_nullable_by_default_if_the_type_is_nullable()).Message); public override void Element_types_can_be_made_required() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Element_types_can_be_made_required()).Message); public override void Element_types_can_have_custom_type_value_converter_type_set() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("int[]", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Element_types_can_have_custom_type_value_converter_type_set()).Message); public override void Element_types_can_have_max_length() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Element_types_can_have_max_length()).Message); public override void Element_types_can_have_non_generic_value_converter_set() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("int[]", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Element_types_can_have_non_generic_value_converter_set()).Message); public override void Element_types_can_have_precision_and_scale() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Element_types_can_have_precision_and_scale()).Message); public override void Element_types_can_have_provider_type_set() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Element_types_can_have_provider_type_set()).Message); public override void Element_types_can_have_unicode_set() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Element_types_can_have_unicode_set()).Message); public override void Element_types_have_default_precision_and_scale() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Element_types_have_default_precision_and_scale()).Message); public override void Element_types_have_default_unicode() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Element_types_have_default_unicode()).Message); public override void Element_types_have_no_max_length_by_default() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Element_types_have_no_max_length_by_default()).Message); public override void Primitive_collections_are_required_by_default_only_if_CLR_type_is_nullable() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Primitive_collections_are_required_by_default_only_if_CLR_type_is_nullable()).Message); public override void Primitive_collections_can_be_made_optional() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Primitive_collections_can_be_made_optional()).Message); public override void Primitive_collections_can_be_made_required() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Primitive_collections_can_be_made_required()).Message); public override void Primitive_collections_can_be_set_to_generate_values_on_Add() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Bottom"), Assert.Throws( () => base.Primitive_collections_can_be_set_to_generate_values_on_Add()).Message); public override void Primitive_collections_can_have_access_mode_set() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("ObservableCollection", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Primitive_collections_can_have_access_mode_set()).Message); public override void Primitive_collections_can_have_field_set() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Down"), + CoreStrings.PropertyNotMapped("ObservableCollection", nameof(CollectionQuarks), "Down"), Assert.Throws( () => base.Primitive_collections_can_have_field_set()).Message); public override void Primitive_collections_can_have_value_converter_set() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Primitive_collections_can_have_value_converter_set()).Message); public override void Primitive_collections_specified_by_string_are_shadow_properties_unless_already_known_to_be_CLR_properties() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("ObservableCollection", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Primitive_collections_specified_by_string_are_shadow_properties_unless_already_known_to_be_CLR_properties()).Message); public override void Value_converter_type_on_primitive_collection_is_checked() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Up"), + CoreStrings.PropertyNotMapped("ObservableCollection", nameof(CollectionQuarks), "Up"), Assert.Throws( () => base.Value_converter_type_on_primitive_collection_is_checked()).Message); @@ -425,7 +425,7 @@ public virtual void No_alternate_key_is_created_if_id_is_partition_key() public override void Primitive_collections_can_be_made_concurrency_tokens() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", nameof(CollectionQuarks), "Charm"), Assert.Throws( () => base.Primitive_collections_can_be_made_concurrency_tokens()).Message); @@ -437,97 +437,97 @@ public class CosmosGenericComplexType : GenericComplexType { public override void Access_mode_can_be_overridden_at_entity_and_property_levels() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Down"), + CoreStrings.PropertyNotMapped("ObservableCollection", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Down"), Assert.Throws( () => base.Access_mode_can_be_overridden_at_entity_and_property_levels()).Message); public override void Can_add_shadow_primitive_collections_when_they_have_been_ignored() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(Customer), "Shadow"), + CoreStrings.PropertyNotMapped("string[]", "ComplexProperties.Customer#Customer", "Shadow"), Assert.Throws( () => base.Can_add_shadow_primitive_collections_when_they_have_been_ignored()).Message); public override void Can_call_PrimitiveCollection_on_a_field() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(EntityWithFields), "CollectionId"), + CoreStrings.PropertyNotMapped("long[]", "ComplexProperties.EntityWithFields#EntityWithFields", "CollectionId"), Assert.Throws( () => base.Can_call_PrimitiveCollection_on_a_field()).Message); public override void Can_set_custom_value_generator_for_primitive_collections() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), + CoreStrings.PropertyNotMapped("List", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Bottom"), Assert.Throws( () => base.Can_set_custom_value_generator_for_primitive_collections()).Message); public override void Can_set_max_length_for_primitive_collections() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), + CoreStrings.PropertyNotMapped("string[]", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Bottom"), Assert.Throws( () => base.Can_set_max_length_for_primitive_collections()).Message); public override void Can_set_primitive_collection_annotation_when_no_clr_property() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(Customer), "Ints"), + CoreStrings.PropertyNotMapped("int[]", "ComplexProperties.Customer#Customer", "Ints"), Assert.Throws( () => base.Can_set_primitive_collection_annotation_when_no_clr_property()).Message); public override void Can_set_sentinel_for_primitive_collections() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), + CoreStrings.PropertyNotMapped("List", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Bottom"), Assert.Throws( () => base.Can_set_sentinel_for_primitive_collections()).Message); public override void Can_set_unicode_for_primitive_collections() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), + CoreStrings.PropertyNotMapped("List", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Bottom"), Assert.Throws( () => base.Can_set_unicode_for_primitive_collections()).Message); public override void Primitive_collections_are_required_by_default_only_if_CLR_type_is_nullable() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Charm"), Assert.Throws( () => base.Primitive_collections_are_required_by_default_only_if_CLR_type_is_nullable()).Message); public override void Primitive_collections_can_be_made_concurrency_tokens() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Charm"), Assert.Throws( () => base.Primitive_collections_can_be_made_concurrency_tokens()).Message); public override void Primitive_collections_can_be_made_optional() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Charm"), Assert.Throws( () => base.Primitive_collections_can_be_made_optional()).Message); public override void Primitive_collections_can_be_made_required() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("List", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Charm"), Assert.Throws( () => base.Primitive_collections_can_be_made_required()).Message); public override void Primitive_collections_can_be_set_to_generate_values_on_Add() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Bottom"), + CoreStrings.PropertyNotMapped("List", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Bottom"), Assert.Throws( () => base.Primitive_collections_can_be_set_to_generate_values_on_Add()).Message); public override void Primitive_collections_can_have_field_set() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Down"), + CoreStrings.PropertyNotMapped("ObservableCollection", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Down"), Assert.Throws( () => base.Primitive_collections_can_have_field_set()).Message); public override void Primitive_collections_specified_by_string_are_shadow_properties_unless_already_known_to_be_CLR_properties() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Charm"), + CoreStrings.PropertyNotMapped("ObservableCollection", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Charm"), Assert.Throws( () => base.Primitive_collections_specified_by_string_are_shadow_properties_unless_already_known_to_be_CLR_properties()).Message); public override void Properties_can_have_access_mode_set() => Assert.Equal( - CosmosStrings.PrimitiveCollectionsNotSupported(nameof(CollectionQuarks), "Down"), + CoreStrings.PropertyNotMapped("ObservableCollection", "ComplexProperties.CollectionQuarks#CollectionQuarks", "Down"), Assert.Throws( () => base.Properties_can_have_access_mode_set()).Message); diff --git a/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs b/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs index 095825c8dd0..fa421eb73b7 100644 --- a/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs @@ -1076,11 +1076,12 @@ public virtual void Can_map_derived_of_owned_type_first() } [ConditionalFact] - public virtual void Can_configure_relationship_with_PK_ValueConverter() + public virtual void Can_configure_relationship_with_PK_ValueConverter_shadow_FK() { var modelBuilder = CreateModelBuilder(); - modelBuilder.Entity().Property(x => x.Id) + modelBuilder.Entity() + .Property(x => x.Id) .HasConversion(x => x.Id, x => new CustomId { Id = x }); modelBuilder.Entity() @@ -1089,8 +1090,7 @@ public virtual void Can_configure_relationship_with_PK_ValueConverter() modelBuilder.Entity() .OwnsOne(q => q.Value) - .Property(x => x.CategoryId) - .HasConversion(x => x.Id, x => new CustomId { Id = x }); + .Property(x => x.CategoryId); var model = modelBuilder.FinalizeModel(); @@ -1106,14 +1106,45 @@ public virtual void Can_configure_relationship_with_PK_ValueConverter() var category = model.FindEntityType(typeof(ValueCategory)); Assert.Null(category.FindProperty("TempId")); - var barNavigation = owned.GetDeclaredNavigations().Single(n => !n.ForeignKey.IsOwnership); - Assert.Same(category, barNavigation.TargetEntityType); - var fkProperty = barNavigation.ForeignKey.Properties.Single(); + var categoryNavigation = owned.GetDeclaredNavigations().Single(n => !n.ForeignKey.IsOwnership); + Assert.Same(category, categoryNavigation.TargetEntityType); + var fkProperty = categoryNavigation.ForeignKey.Properties.Single(); Assert.Equal("CategoryId", fkProperty.Name); Assert.Equal(3, model.GetEntityTypes().Count()); } + [ConditionalFact] + public virtual void Can_configure_relationship_with_PK_ValueConverter() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity(eb => + { + eb.Property(x => x.Id) + .HasConversion(x => x.Id, x => new CustomId { Id = x }); + eb.OwnsOne(q => q.Value) + .WithOwner() + .HasForeignKey(q => q.CategoryId); + }); + + modelBuilder.Ignore(); + + var model = modelBuilder.FinalizeModel(); + + var result = model.FindEntityType(typeof(QueryResult)); + Assert.Null(result.FindProperty("TempId")); + + var owned = result.GetDeclaredNavigations().Single().TargetEntityType; + Assert.Null(owned.FindProperty("TempId")); + + var ownedPkProperty = owned.FindPrimaryKey().Properties.Single(); + Assert.NotNull(ownedPkProperty.GetValueConverter()); + + Assert.Empty(owned.GetDeclaredNavigations().Where(n => !n.ForeignKey.IsOwnership)); + Assert.Equal(2, model.GetEntityTypes().Count()); + } + [ConditionalFact] public virtual void Throws_on_FK_matching_two_relationships() { diff --git a/test/EFCore.Tests/ModelBuilding/TestModel.cs b/test/EFCore.Tests/ModelBuilding/TestModel.cs index 215ec576aaf..cc1a81e459e 100644 --- a/test/EFCore.Tests/ModelBuilding/TestModel.cs +++ b/test/EFCore.Tests/ModelBuilding/TestModel.cs @@ -3,6 +3,7 @@ #nullable enable +using System.Collections; using System.Collections.ObjectModel; using System.ComponentModel; using System.ComponentModel.DataAnnotations; @@ -809,9 +810,12 @@ protected class Value public ValueCategory? Category { get; set; } } - protected class CustomId + protected class CustomId : IEnumerable { public int Id { get; set; } + + public IEnumerator GetEnumerator() => throw new NotImplementedException(); + IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); } protected class ValueCategory From 1582f80b412fb755c9b5923ecacf4e3f61188fc8 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Tue, 3 Sep 2024 15:55:36 -0700 Subject: [PATCH 30/32] [release/9.0] Generate correct calls for complex and primitive properties in the model snapshot (#34587) Fixes #34578 --- .../Design/CSharpSnapshotGenerator.cs | 3 +- .../SqlServerAnnotationCodeGenerator.cs | 62 +++++++++-- ...rpMigrationsGeneratorTest.ModelSnapshot.cs | 103 ++++++++++++++++-- 3 files changed, 147 insertions(+), 21 deletions(-) diff --git a/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs b/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs index 291952bca9d..d5efd7f6a81 100644 --- a/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs +++ b/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs @@ -443,7 +443,8 @@ protected virtual void GenerateProperty( var clrType = (FindValueConverter(property)?.ProviderClrType ?? property.ClrType) .MakeNullable(property.IsNullable); - var propertyBuilderName = $"{entityTypeBuilderName}.Property<{Code.Reference(clrType)}>({Code.Literal(property.Name)})"; + var propertyCall = property.IsPrimitiveCollection ? "PrimitiveCollection" : "Property"; + var propertyBuilderName = $"{entityTypeBuilderName}.{propertyCall}<{Code.Reference(clrType)}>({Code.Literal(property.Name)})"; stringBuilder .AppendLine() diff --git a/src/EFCore.SqlServer/Design/Internal/SqlServerAnnotationCodeGenerator.cs b/src/EFCore.SqlServer/Design/Internal/SqlServerAnnotationCodeGenerator.cs index 875567bd1b7..01e6918c559 100644 --- a/src/EFCore.SqlServer/Design/Internal/SqlServerAnnotationCodeGenerator.cs +++ b/src/EFCore.SqlServer/Design/Internal/SqlServerAnnotationCodeGenerator.cs @@ -55,18 +55,42 @@ private static readonly MethodInfo PropertyIsSparseMethodInfo = typeof(SqlServerPropertyBuilderExtensions).GetRuntimeMethod( nameof(SqlServerPropertyBuilderExtensions.IsSparse), [typeof(PropertyBuilder), typeof(bool)])!; + private static readonly MethodInfo PrimitiveCollectionIsSparseMethodInfo + = typeof(SqlServerPrimitiveCollectionBuilderExtensions).GetRuntimeMethod( + nameof(SqlServerPrimitiveCollectionBuilderExtensions.IsSparse), [typeof(PrimitiveCollectionBuilder), typeof(bool)])!; + + private static readonly MethodInfo ComplexTypePropertyIsSparseMethodInfo + = typeof(SqlServerComplexTypePropertyBuilderExtensions).GetRuntimeMethod( + nameof(SqlServerComplexTypePropertyBuilderExtensions.IsSparse), [typeof(ComplexTypePropertyBuilder), typeof(bool)])!; + + private static readonly MethodInfo ComplexTypePrimitiveCollectionIsSparseMethodInfo + = typeof(SqlServerComplexTypePrimitiveCollectionBuilderExtensions).GetRuntimeMethod( + nameof(SqlServerComplexTypePrimitiveCollectionBuilderExtensions.IsSparse), [typeof(ComplexTypePrimitiveCollectionBuilder), typeof(bool)])!; + private static readonly MethodInfo PropertyUseIdentityColumnsMethodInfo = typeof(SqlServerPropertyBuilderExtensions).GetRuntimeMethod( nameof(SqlServerPropertyBuilderExtensions.UseIdentityColumn), [typeof(PropertyBuilder), typeof(long), typeof(int)])!; + private static readonly MethodInfo ComplexTypePropertyUseIdentityColumnsMethodInfo + = typeof(SqlServerComplexTypePropertyBuilderExtensions).GetRuntimeMethod( + nameof(SqlServerComplexTypePropertyBuilderExtensions.UseIdentityColumn), [typeof(ComplexTypePropertyBuilder), typeof(long), typeof(int)])!; + private static readonly MethodInfo PropertyUseHiLoMethodInfo = typeof(SqlServerPropertyBuilderExtensions).GetRuntimeMethod( nameof(SqlServerPropertyBuilderExtensions.UseHiLo), [typeof(PropertyBuilder), typeof(string), typeof(string)])!; + private static readonly MethodInfo ComplexTypePropertyUseHiLoMethodInfo + = typeof(SqlServerComplexTypePropertyBuilderExtensions).GetRuntimeMethod( + nameof(SqlServerComplexTypePropertyBuilderExtensions.UseHiLo), [typeof(ComplexTypePropertyBuilder), typeof(string), typeof(string)])!; + private static readonly MethodInfo PropertyUseSequenceMethodInfo = typeof(SqlServerPropertyBuilderExtensions).GetRuntimeMethod( nameof(SqlServerPropertyBuilderExtensions.UseSequence), [typeof(PropertyBuilder), typeof(string), typeof(string)])!; + private static readonly MethodInfo ComplexTypePropertyUseSequenceMethodInfo + = typeof(SqlServerComplexTypePropertyBuilderExtensions).GetRuntimeMethod( + nameof(SqlServerComplexTypePropertyBuilderExtensions.UseSequence), [typeof(ComplexTypePropertyBuilder), typeof(string), typeof(string)])!; + private static readonly MethodInfo IndexIsClusteredMethodInfo = typeof(SqlServerIndexBuilderExtensions).GetRuntimeMethod( nameof(SqlServerIndexBuilderExtensions.IsClustered), [typeof(IndexBuilder), typeof(bool)])!; @@ -144,7 +168,7 @@ public override IReadOnlyList GenerateFluentApiCalls( { var fragments = new List(base.GenerateFluentApiCalls(model, annotations)); - if (GenerateValueGenerationStrategy(annotations, model, onModel: true) is MethodCallCodeFragment valueGenerationStrategy) + if (GenerateValueGenerationStrategy(annotations, model, onModel: true, complexType: false) is MethodCallCodeFragment valueGenerationStrategy) { fragments.Add(valueGenerationStrategy); } @@ -179,7 +203,9 @@ public override IReadOnlyList GenerateFluentApiCalls( { var fragments = new List(base.GenerateFluentApiCalls(property, annotations)); - if (GenerateValueGenerationStrategy(annotations, property.DeclaringType.Model, onModel: false) is MethodCallCodeFragment + var isPrimitiveCollection = property.IsPrimitiveCollection; + + if (GenerateValueGenerationStrategy(annotations, property.DeclaringType.Model, onModel: false, complexType: property.DeclaringType is IComplexType) is MethodCallCodeFragment valueGenerationStrategy) { fragments.Add(valueGenerationStrategy); @@ -187,10 +213,17 @@ public override IReadOnlyList GenerateFluentApiCalls( if (GetAndRemove(annotations, SqlServerAnnotationNames.Sparse) is bool isSparse) { + var methodInfo = isPrimitiveCollection + ? property.DeclaringType is IComplexType + ? ComplexTypePrimitiveCollectionIsSparseMethodInfo + : PrimitiveCollectionIsSparseMethodInfo + : property.DeclaringType is IComplexType + ? ComplexTypePropertyIsSparseMethodInfo + : PropertyIsSparseMethodInfo; fragments.Add( isSparse - ? new MethodCallCodeFragment(PropertyIsSparseMethodInfo) - : new MethodCallCodeFragment(PropertyIsSparseMethodInfo, false)); + ? new MethodCallCodeFragment(methodInfo) + : new MethodCallCodeFragment(methodInfo, false)); } return fragments; @@ -367,7 +400,8 @@ protected override bool IsHandledByConvention(IProperty property, IAnnotation an private static MethodCallCodeFragment? GenerateValueGenerationStrategy( IDictionary annotations, IModel model, - bool onModel) + bool onModel, + bool complexType) { SqlServerValueGenerationStrategy strategy; if (annotations.TryGetValue(SqlServerAnnotationNames.ValueGenerationStrategy, out var strategyAnnotation) @@ -405,7 +439,11 @@ protected override bool IsHandledByConvention(IProperty property, IAnnotation an ?? model.FindAnnotation(SqlServerAnnotationNames.IdentityIncrement)?.Value as int? ?? 1; return new MethodCallCodeFragment( - onModel ? ModelUseIdentityColumnsMethodInfo : PropertyUseIdentityColumnsMethodInfo, + onModel + ? ModelUseIdentityColumnsMethodInfo + : complexType + ? ComplexTypePropertyUseIdentityColumnsMethodInfo + : PropertyUseIdentityColumnsMethodInfo, (seed, increment) switch { (1L, 1) => [], @@ -418,7 +456,11 @@ protected override bool IsHandledByConvention(IProperty property, IAnnotation an var name = GetAndRemove(annotations, SqlServerAnnotationNames.HiLoSequenceName); var schema = GetAndRemove(annotations, SqlServerAnnotationNames.HiLoSequenceSchema); return new MethodCallCodeFragment( - onModel ? ModelUseHiLoMethodInfo : PropertyUseHiLoMethodInfo, + onModel + ? ModelUseHiLoMethodInfo + : complexType + ? ComplexTypePropertyUseHiLoMethodInfo + : PropertyUseHiLoMethodInfo, (name, schema) switch { (null, null) => [], @@ -435,7 +477,11 @@ protected override bool IsHandledByConvention(IProperty property, IAnnotation an var schema = GetAndRemove(annotations, SqlServerAnnotationNames.SequenceSchema); return new MethodCallCodeFragment( - onModel ? ModelUseKeySequencesMethodInfo : PropertyUseSequenceMethodInfo, + onModel + ? ModelUseKeySequencesMethodInfo + : complexType + ? ComplexTypePropertyUseSequenceMethodInfo + : PropertyUseSequenceMethodInfo, (name: nameOrSuffix, schema) switch { (null, null) => [], diff --git a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs index a3ac3eff14b..d9216f9dfe5 100644 --- a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs +++ b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.ModelSnapshot.cs @@ -5944,6 +5944,72 @@ public virtual void SQLServer_property_legacy_identity_seed_int_annotation() #endregion + #region Primitive collection + + [ConditionalFact] + public virtual void PrimitiveCollection_is_stored_in_snapshot() + => Test( + builder => + { + builder.Entity() + .PrimitiveCollection>("List") + .IsSparse() + .IsFixedLength() + .HasMaxLength(100) + .IsUnicode() + .UseCollation("ListCollation") + .HasSentinel([]) + .HasColumnName("ListColumn") + .HasColumnType("nvarchar") + .HasColumnOrder(1) + .HasComment("ListComment") + .HasComputedColumnSql("ListSql") + .HasJsonPropertyName("ListJson") + .ElementType(b => b.HasConversion()) + .ValueGeneratedOnUpdateSometimes() + .HasAnnotation("AnnotationName", "AnnotationValue"); + + builder.Ignore(); + }, + AddBoilerPlate( + GetHeading() + + """ + modelBuilder.Entity("Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGeneratorTest+EntityWithOneProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.PrimitiveCollection("List") + .ValueGeneratedOnUpdateSometimes() + .HasMaxLength(100) + .IsUnicode(true) + .HasColumnType("nvarchar") + .HasColumnName("ListColumn") + .HasColumnOrder(1) + .HasComputedColumnSql("ListSql") + .IsFixedLength() + .HasComment("ListComment") + .UseCollation("ListCollation") + .HasAnnotation("AnnotationName", "AnnotationValue") + .HasAnnotation("Relational:JsonPropertyName", "ListJson"); + + SqlServerPrimitiveCollectionBuilderExtensions.IsSparse(b.PrimitiveCollection("List")); + + b.HasKey("Id"); + + b.ToTable("EntityWithOneProperty", "DefaultSchema"); + }); +"""), + o => + { + var property = o.GetEntityTypes().First().FindProperty("List"); + Assert.Equal("AnnotationValue", property["AnnotationName"]); + }); + #endregion + #region Complex types [ConditionalFact] @@ -5958,8 +6024,13 @@ public virtual void Complex_properties_are_stored_in_snapshot() eo => eo.EntityWithTwoProperties, eb => { eb.IsRequired(); - eb.Property(e => e.AlternateId).HasColumnOrder(1); - eb.ComplexProperty(e => e.EntityWithStringKey).IsRequired(); + eb.Property(e => e.AlternateId).HasColumnOrder(1).IsSparse(); + eb.PrimitiveCollection>("List") + .HasColumnType("nvarchar(max)") + .IsSparse(); + eb.ComplexProperty(e => e.EntityWithStringKey) + .IsRequired() + .Ignore(e => e.Properties); eb.HasPropertyAnnotation("PropertyAnnotation", 1); eb.HasTypeAnnotation("TypeAnnotation", 2); }); @@ -5984,9 +6055,16 @@ public virtual void Complex_properties_are_stored_in_snapshot() .HasColumnType("int") .HasColumnOrder(1); + SqlServerComplexTypePropertyBuilderExtensions.IsSparse(b1.Property("AlternateId")); + b1.Property("Id") .HasColumnType("int"); + b1.PrimitiveCollection("List") + .HasColumnType("nvarchar(max)"); + + SqlServerComplexTypePrimitiveCollectionBuilderExtensions.IsSparse(b1.PrimitiveCollection("List")); + b1.ComplexProperty>("EntityWithStringKey", "Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGeneratorTest+EntityWithOneProperty.EntityWithTwoProperties#EntityWithTwoProperties.EntityWithStringKey#EntityWithStringKey", b2 => { b2.IsRequired(); @@ -6005,7 +6083,7 @@ public virtual void Complex_properties_are_stored_in_snapshot() b.ToTable("EntityWithOneProperty", "DefaultSchema"); }); """, usingCollections: true), - o => + (_, o) => { var entityWithOneProperty = o.FindEntityType(typeof(EntityWithOneProperty)); Assert.Equal(nameof(EntityWithOneProperty), entityWithOneProperty.GetTableName()); @@ -6037,7 +6115,8 @@ public virtual void Complex_properties_are_stored_in_snapshot() Assert.Equal(nameof(EntityWithOneProperty), nestedComplexType.GetTableName()); var nestedIdProperty = nestedComplexType.FindProperty(nameof(EntityWithStringKey.Id)); Assert.True(nestedIdProperty.IsNullable); - }); + }, + validate: true); #endregion @@ -7981,7 +8060,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - b.Property("BoolCollection") + b.PrimitiveCollection("BoolCollection") .HasColumnType("nvarchar(max)"); b.Property("Boolean") @@ -7993,7 +8072,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Bytes") .HasColumnType("varbinary(max)"); - b.Property("BytesCollection") + b.PrimitiveCollection("BytesCollection") .HasColumnType("nvarchar(max)"); b.Property("Character") @@ -8003,7 +8082,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("DateTime") .HasColumnType("datetime2"); - b.Property("DateTimeCollection") + b.PrimitiveCollection("DateTimeCollection") .HasColumnType("nvarchar(max)"); b.Property("DateTimeOffset") @@ -8015,7 +8094,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Double") .HasColumnType("float"); - b.Property("DoubleCollection") + b.PrimitiveCollection("DoubleCollection") .HasColumnType("nvarchar(max)"); b.Property("Enum16") @@ -8048,7 +8127,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Int32") .HasColumnType("int"); - b.Property("Int32Collection") + b.PrimitiveCollection("Int32Collection") .HasColumnType("nvarchar(max)"); b.Property("Int64") @@ -8108,7 +8187,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("String") .HasColumnType("nvarchar(max)"); - b.Property("StringCollection") + b.PrimitiveCollection("StringCollection") .HasColumnType("nvarchar(max)"); b.Property("TimeSpan") @@ -8403,7 +8482,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) protected void Test(Action buildModel, string expectedCode, Action assert) => Test(buildModel, expectedCode, (m, _) => assert(m)); - protected void Test(Action buildModel, string expectedCode, Action assert) + protected void Test(Action buildModel, string expectedCode, Action assert, bool validate = false) { var modelBuilder = CreateConventionalModelBuilder(); modelBuilder.HasDefaultSchema("DefaultSchema"); @@ -8411,7 +8490,7 @@ protected void Test(Action buildModel, string expectedCode, Action modelBuilder.Model.RemoveAnnotation(CoreAnnotationNames.ProductVersion); buildModel(modelBuilder); - var model = modelBuilder.FinalizeModel(designTime: true, skipValidation: true); + var model = modelBuilder.FinalizeModel(designTime: true, skipValidation: !validate); Test(model, expectedCode, assert); } From b6bd805c86c1ae85dedb328dfbea56270386923d Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Wed, 4 Sep 2024 10:22:59 -0700 Subject: [PATCH 31/32] Update Azure.Identity version (#34605) --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index f22b3095840..5350252095a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -39,7 +39,7 @@ 4.8.0 1.1.2-beta1.24121.1 - 1.11.3 + 1.12.0 1.3.2 1.8.1 From bc97c2c058f2d5f7dd8b39180632c6e347cebf85 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Wed, 4 Sep 2024 11:51:10 -0700 Subject: [PATCH 32/32] [release/9.0] Update Mono.TextTemplating and Microsoft.CodeAnalysis to non-preview versions (#34606) --- src/EFCore.Design/EFCore.Design.csproj | 2 +- test/EFCore.Design.Tests/EFCore.Design.Tests.csproj | 2 +- .../EFCore.Relational.Specification.Tests.csproj | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/EFCore.Design/EFCore.Design.csproj b/src/EFCore.Design/EFCore.Design.csproj index 586c8a32753..cfb2ac7b165 100644 --- a/src/EFCore.Design/EFCore.Design.csproj +++ b/src/EFCore.Design/EFCore.Design.csproj @@ -62,7 +62,7 @@ - + diff --git a/test/EFCore.Design.Tests/EFCore.Design.Tests.csproj b/test/EFCore.Design.Tests/EFCore.Design.Tests.csproj index e7ff39b5371..36abc41e4cf 100644 --- a/test/EFCore.Design.Tests/EFCore.Design.Tests.csproj +++ b/test/EFCore.Design.Tests/EFCore.Design.Tests.csproj @@ -56,7 +56,7 @@ - + diff --git a/test/EFCore.Relational.Specification.Tests/EFCore.Relational.Specification.Tests.csproj b/test/EFCore.Relational.Specification.Tests/EFCore.Relational.Specification.Tests.csproj index e3e6935f96b..94f59331dcb 100644 --- a/test/EFCore.Relational.Specification.Tests/EFCore.Relational.Specification.Tests.csproj +++ b/test/EFCore.Relational.Specification.Tests/EFCore.Relational.Specification.Tests.csproj @@ -50,10 +50,8 @@ - - - - + +