DbTransaction.SupportsSavepoints docs say Release/ReleaseAsync are expected to throw, but they are no-ops by design

Aperta Adatta ai principianti
#137,040 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

@alaricd ci sta già lavorando.

Dal 5/11/2026.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
72/100
Tipo di issue
Documentazione
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
csharp
Ambito
documentation

Direzione di ricerca

Inizia dal commento XML di SupportsSavepoints in DbTransaction.cs e confrontalo con le implementazioni predefinite di Release e ReleaseAsync e con le note API in #33397. Aggiorna il commento per descrivere quali metodi generano eccezioni e che i metodi di rilascio non fanno nulla per impostazione predefinita; controlla i test di documentazione vicini e aggiungi copertura per il comportamento descritto. Il lavoro è concluso quando la documentazione corrisponde all’implementazione e i test passano.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

area-System.Transactions untriaged
Description

The documentation of DbTransaction.SupportsSavepoints says that when it is false, SaveAsync, RollbackAsync and ReleaseAsync "as well as their synchronous counterparts are expected to throw NotSupportedException". The default implementations do not do that for Release/ReleaseAsync: they are deliberate no-ops.

public virtual void Save(string savepointName) => throw new NotSupportedException();
public virtual void Rollback(string savepointName) => throw new NotSupportedException();
public virtual void Release(string savepointName) { }

This matches the approved API shape in #33397, whose notes say a Release no-op by default "seems correct ... as opposed to the other methods which throw if not supported", because releasing has no user-visible behavior and should generally not throw. So the implementation looks intentional and the documentation sentence is the part that is out of step. The same sentence is the one published on learn.microsoft.com for DbTransaction.SupportsSavepoints. The Release and ReleaseAsync pages themselves say nothing about throwing.

I am not proposing a behavior change. A provider author who reads the SupportsSavepoints sentence (or a test author who builds a conformance test from it) will expect Release to throw when savepoints are unsupported, and every provider that does not override Release will appear to violate it.

Reproduction Steps

No database is needed. A transaction that overrides no savepoint member, on .NET 10:

using System;
using System.Data;
using System.Data.Common;
using System.Threading.Tasks;

using var transaction = new NoSavepointTransaction();
Console.WriteLine($"SupportsSavepoints = {transaction.SupportsSavepoints}");
Try("Save", () => transaction.Save("sp"));
Try("Rollback(string)", () => transaction.Rollback("sp"));
Try("Release", () => transaction.Release("sp"));
await TryAsync("SaveAsync", () => transaction.SaveAsync("sp"));
await TryAsync("RollbackAsync(string)", () => transaction.RollbackAsync("sp"));
await TryAsync("ReleaseAsync", () => transaction.ReleaseAsync("sp"));

static void Try(string name, Action action)
{
    try { action(); Console.WriteLine($"{name}: no exception"); }
    catch (Exception e) { Console.WriteLine($"{name}: {e.GetType().Name}"); }
}

static async Task TryAsync(string name, Func<Task> action)
{
    try { await action(); Console.WriteLine($"{name}: no exception"); }
    catch (Exception e) { Console.WriteLine($"{name}: {e.GetType().Name}"); }
}

sealed class NoSavepointTransaction : DbTransaction
{
    public override IsolationLevel IsolationLevel => IsolationLevel.ReadCommitted;
    protected override DbConnection? DbConnection => null;
    public override void Commit() { }
    public override void Rollback() { }
}
Expected behavior

The documentation and the implementation agree. Given #33397, the documentation should say that Save/SaveAsync and Rollback(string)/RollbackAsync are expected to throw NotSupportedException when SupportsSavepoints is false, and that Release/ReleaseAsync do nothing by default.

Actual behavior
SupportsSavepoints = False
Save: NotSupportedException
Rollback(string): NotSupportedException
Release: no exception
SaveAsync: NotSupportedException
RollbackAsync(string): NotSupportedException
ReleaseAsync: no exception
Regression?

No. The documentation and the implementation have read this way since they were added.

Known Workarounds

None needed at runtime. Provider authors and test authors have to know that Release is the exception to the documented sentence.

Configuration

.NET 10, Windows 10 x64. The behavior is in System.Data.Common and does not depend on a provider.

Other information

The source of the sentence is the XML comment on SupportsSavepoints in DbTransaction.cs. I plan to send a PR that corrects that comment and adds tests pinning the default behavior of all six savepoint members, unless you would rather change the behavior or the wording.

Found with the pengdows.AdoNetApiTest.conformance suite, an xUnit conformance suite for ADO.NET providers. Its savepoint tests asserted that Release throws, which is how this surfaced; the suite is being corrected as well.

Lingua principale
C#
Stelle
18.4k
Fork
5.8k
Merge medio
2g 17h
PR unite (30g)
581

Preparare l'ambiente

Apri in Codespaces

Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di dotnet/runtime

Tutte le issue di dotnet/runtime

Issue simili

Altre issue su C#

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.