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

Đang mở Phù hợp với người mới
#137,040 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

@alaricd đang làm issue này rồi.

Từ ngày 5/11/2026.

  • #137042 của @alaricd — đang mở

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
72/100
Loại issue
Tài liệu
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
csharp
Lĩnh vực
documentation

Hướng nghiên cứu

Bắt đầu với chú thích XML cho SupportsSavepoints trong DbTransaction.cs và so sánh với các phần triển khai mặc định của Release và ReleaseAsync, cùng các ghi chú API trong #33397. Cập nhật chú thích để mô tả những phương thức nào ném ngoại lệ và rằng các phương thức giải phóng mặc định không làm gì; kiểm tra các bài kiểm thử tài liệu gần đó và bổ sung kiểm thử cho hành vi được nêu. Hoàn tất khi tài liệu khớp với phần triển khai và các bài kiểm thử đều đạt.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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.

Ngôn ngữ chính
C#
Star
18.4k
Fork
5.8k
Merge trung bình
2 ngày 17 giờ
Pull request đã merge (30 ngày)
581

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của dotnet/runtime

Tất cả issue của dotnet/runtime

Issue tương tự

Thêm issue về C#

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.