Skip to content

Fix NpgsqlOptionsExtension losing ParameterizedCollectionMode between clones#3796

Merged
roji merged 3 commits intomainfrom
copilot/fix-npgsql-options-extension-parameterized-collect
Mar 31, 2026
Merged

Fix NpgsqlOptionsExtension losing ParameterizedCollectionMode between clones#3796
roji merged 3 commits intomainfrom
copilot/fix-npgsql-options-extension-parameterized-collect

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 30, 2026

_parameterizedCollectionMode was not copied in the NpgsqlOptionsExtension copy constructor, so any WithXyz call (which clones internally) would silently reset it to the default.

options.UseNpgsql("connection", s => {
    s.UseParameterizedCollectionMode(ParameterTranslationMode.MultipleParameters);
    s.UsePostgresVersion(new Version(17, 0)); // clone here drops the mode
});

// Was: ParameterTranslationMode.Parameter (wrong)
// Now: ParameterTranslationMode.MultipleParameters (correct)
  • Fix: Add _parameterizedCollectionMode = copyFrom._parameterizedCollectionMode to the copy constructor, consistent with all other fields
  • Test: Add ParameterizedCollectionMode_is_preserved_after_clone covering the reported scenario

Fixes #3795

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 80zvsblobprodcus35.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/EFCore.PG.slnx --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/test/EFCore.PG.Tests/EFCore.PG.Tests.csproj --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true dcca�� cture/Internal/N--irreversible-delete (dns block)
  • 8xbvsblobprodcus382.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/EFCore.PG.slnx --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/test/EFCore.PG.FunctionalTests/EFCore.PG.FunctionalTests.csproj --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true dcca�� (dns block)
  • i1qvsblobprodcus353.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/EFCore.PG.slnx --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/test/EFCore.PG.Tests/EFCore.PG.Tests.csproj --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true dcca�� cture/Internal/N--irreversible-delete (dns block)
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/test/EFCore.PG.FunctionalTests/EFCore.PG.FunctionalTests.csproj --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true dcca�� (dns block)
  • jrqvsblobprodcus343.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/EFCore.PG.slnx --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/src/EFCore.PG/EFCore.PG.csproj --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true dcca�� (dns block)
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/src/EFCore.PG.NodaTime/EFCore.PG.NodaTime.csproj --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true dcca�� cture/Internal/N--irreversible-delete (dns block)
  • p2ovsblobprodcus312.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/EFCore.PG.slnx --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/src/EFCore.PG/EFCore.PG.csproj --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true dcca�� (dns block)
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/src/EFCore.PG.NodaTime/EFCore.PG.NodaTime.csproj --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true dcca�� cture/Internal/N--irreversible-delete (dns block)
  • rcxvsblobprodcus328.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/EFCore.PG.slnx --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/test/EFCore.PG.FunctionalTests/EFCore.PG.FunctionalTests.csproj --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true dcca�� (dns block)
  • uy6vsblobprodcus34.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/EFCore.PG.slnx --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/test/EFCore.PG.Tests/EFCore.PG.Tests.csproj --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true dcca�� cture/Internal/N--irreversible-delete (dns block)
  • www.myget.org
    • Triggering command: /usr/bin/dotnet dotnet test test/EFCore.PG.Tests --filter FullyQualifiedName~NpgsqlDbContextOptionsExtensionsTest.ParameterizedCollectionMode_is_preserved_after_clone (dns block)
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.24.3/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp /opt/hostedtoolcache/CodeQL/2.24.3/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp b3274879af910afc769298a2b2f5c230ece/5d4be8c5d6383d214128a8999c0e11ab23f3ef60a787028b�� (dns block)
    • Triggering command: /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /home/REDACTED/work/efcore.pg/efcore.pg/EFCore.PG.slnx --packages /tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-a20bfa1f1f244e03/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI linked an issue Mar 30, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Fix NpgsqlOptionsExtension losing ParameterizedCollectionMode in clones Fix NpgsqlOptionsExtension losing ParameterizedCollectionMode between clones Mar 30, 2026
Copilot AI requested a review from roji March 30, 2026 18:24
Copilot finished work on behalf of roji March 30, 2026 18:25
@roji roji marked this pull request as ready for review March 30, 2026 18:37
Copilot AI review requested due to automatic review settings March 30, 2026 18:37
@roji roji enabled auto-merge (squash) March 30, 2026 18:37
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes an options-cloning bug in NpgsqlOptionsExtension where ParameterizedCollectionMode was unintentionally reset to default when the extension was cloned (e.g., via subsequent WithXyz option calls), and adds a regression test to ensure the mode is preserved.

Changes:

  • Copy _parameterizedCollectionMode in NpgsqlOptionsExtension copy constructor to preserve it across clones.
  • Add a unit test asserting ParameterizedCollectionMode survives an additional options call that triggers cloning.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/EFCore.PG/Infrastructure/Internal/NpgsqlOptionsExtension.cs Copies _parameterizedCollectionMode in the copy ctor to prevent loss during Clone()/WithXyz chaining.
test/EFCore.PG.Tests/NpgsqlDbContextOptionsExtensionsTest.cs Adds regression coverage asserting the configured ParameterizedCollectionMode remains after a subsequent option mutation.

@roji roji disabled auto-merge March 31, 2026 06:57
Copilot AI and others added 3 commits March 31, 2026 10:01
… clones

Add _parameterizedCollectionMode to the copy constructor so the value
is preserved when Clone() is called by any WithXyz method.

Add test verifying the mode survives a subsequent UsePostgresVersion call.

Agent-Logs-Url: https://github.com/npgsql/efcore.pg/sessions/6210ab26-9cbe-4297-b483-d782610e68e9

Co-authored-by: roji <1862641+roji@users.noreply.github.com>
@roji roji force-pushed the copilot/fix-npgsql-options-extension-parameterized-collect branch from f34309b to b81cad0 Compare March 31, 2026 08:01
@roji roji merged commit 9119f83 into main Mar 31, 2026
14 checks passed
@roji roji deleted the copilot/fix-npgsql-options-extension-parameterized-collect branch March 31, 2026 08:50
roji added a commit that referenced this pull request Mar 31, 2026
… clones (#3796)

Fixes #3795

Co-authored-by: Shay Rojansky <roji@roji.org>
(cherry picked from commit 9119f83)
@roji
Copy link
Copy Markdown
Member

roji commented Mar 31, 2026

Backported to 10.0.2 via 632d7fb

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NpgsqlOptionsExtension loses ParameterizedCollectionMode between clones

3 participants