Skip to content

Commit ad5f445

Browse files
authored
Merge pull request #2227 from Tangtang1997/fix-issue2226
fix: UnitOfWork.Dispose后未禁用Enable导致孤儿事务和连接泄漏
2 parents e007d0f + 3ac73ee commit ad5f445

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

FreeSql.DbContext/UnitOfWork/UnitOfWork.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ public void Dispose()
172172
}
173173
finally
174174
{
175+
Enable = false;
175176
_fsql?.Aop.TraceAfterHandler?.Invoke(this, new Aop.TraceAfterEventArgs(_uowBefore, "释放", null));
176177
GC.SuppressFinalize(this);
177178
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using FreeSql.DataAnnotations;
2+
using Xunit;
3+
4+
namespace FreeSql.Tests.Issues;
5+
6+
public class _2226
7+
{
8+
9+
[Table(Name = "issue9999_order")]
10+
class TestOrder
11+
{
12+
[Column(IsIdentity = true)]
13+
public int Id { get; set; }
14+
15+
public string Name { get; set; }
16+
}
17+
18+
/// <summary>
19+
/// UnitOfWork.Dispose 后,绑定了该 UoW 的 Repository 执行写操作
20+
/// 不应开启孤儿事务,应走 auto-commit 正常持久化
21+
/// </summary>
22+
[Fact]
23+
public void UnitOfWorkDispose_ShouldPreventOrphanTransaction()
24+
{
25+
var fsql = g.sqlite;
26+
fsql.Delete<TestOrder>().Where("1=1").ExecuteAffrows();
27+
28+
var repo = fsql.GetRepository<TestOrder>();
29+
30+
// 阶段一:在 UoW 内插入并提交
31+
using (var uow = fsql.CreateUnitOfWork())
32+
{
33+
repo.UnitOfWork = uow;
34+
repo.Insert(new TestOrder { Name = "test" });
35+
uow.Commit();
36+
}
37+
// UoW 已 Dispose,但 repo.UnitOfWork 仍指向它
38+
39+
// 阶段二:通过残留 UoW 引用的 repo 执行更新
40+
// 修复前:GetOrBeginTransaction 在已 Dispose 的 UoW 上开启新事务,永无 Commit,成为孤儿
41+
// 修复后:Enable=false → GetOrBeginTransaction 返回 null → auto-commit
42+
var item = repo.Select.First();
43+
Assert.NotNull(item);
44+
45+
item.Name = "test_updated";
46+
repo.Update(item);
47+
48+
// 用独立查询验证更新已持久化(非孤儿事务中的不可见数据)
49+
var updated = fsql.Select<TestOrder>().Where(a => a.Id == item.Id).First();
50+
Assert.Equal("test_updated", updated.Name);
51+
}
52+
53+
/// <summary>
54+
/// UnitOfWork.Dispose 后 Enable 应为 false,
55+
/// GetOrBeginTransaction 应返回 null 而非创建新事务
56+
/// </summary>
57+
[Fact]
58+
public void UnitOfWorkDispose_ShouldSetEnableFalse()
59+
{
60+
var fsql = g.sqlite;
61+
62+
var uow = fsql.CreateUnitOfWork();
63+
var concreteUow = (UnitOfWork)uow;
64+
Assert.True(concreteUow.Enable);
65+
66+
uow.Commit();
67+
uow.Dispose();
68+
69+
// 修复后 Dispose 将 Enable 设为 false
70+
Assert.False(concreteUow.Enable);
71+
72+
// Enable=false 时 GetOrBeginTransaction 应返回 null,不创建新事务
73+
var tran = uow.GetOrBeginTransaction();
74+
Assert.Null(tran);
75+
}
76+
}

0 commit comments

Comments
 (0)