Skip to content

Fix NpgsqlOptionsExtension losing ParameterizedCollectionMode between clones#3796

Open
Copilot wants to merge 3 commits intomainfrom
copilot/fix-npgsql-options-extension-parameterized-collect
Open

Fix NpgsqlOptionsExtension losing ParameterizedCollectionMode between clones#3796
Copilot wants to merge 3 commits intomainfrom
copilot/fix-npgsql-options-extension-parameterized-collect

Conversation

Copy link
Copy Markdown

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:

… 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>
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.

Comment on lines +33 to +37
optionsBuilder.UseNpgsql("Database=Crunchie", b =>
{
b.UseParameterizedCollectionMode(ParameterTranslationMode.MultipleParameters);
b.UseRelationalNulls();
});
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

The PR description/example references UsePostgresVersion(...), but this repo's public options API appears to be SetPostgresVersion(...) (no UsePostgresVersion found under src/). Consider updating the PR description and/or adjusting this regression test to use SetPostgresVersion so it matches the reported scenario and is easier to understand.

Copilot uses AI. Check for mistakes.
@roji roji disabled auto-merge March 31, 2026 06:57
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