mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 02:32:50 +08:00
- 增加 UnitOfWorkManager 工作单元管理器,实现多种传播事务;#289
This commit is contained in:
parent
2e62db563d
commit
5e15749aa8
@ -0,0 +1,70 @@
|
|||||||
|
using FreeSql;
|
||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace aspnetcore_transaction.Controllers
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("")]
|
||||||
|
public class HomeController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ILogger<HomeController> _logger;
|
||||||
|
|
||||||
|
public HomeController(ILogger<HomeController> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
//[Transactional]
|
||||||
|
virtual public object Get([FromServices] BaseRepository<Song> repoSong, [FromServices] BaseRepository<Detail> repoDetail, [FromServices] SongRepository repoSong2,
|
||||||
|
[FromServices] SongService serviceSong)
|
||||||
|
{
|
||||||
|
serviceSong.Test();
|
||||||
|
return "111";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SongService
|
||||||
|
{
|
||||||
|
BaseRepository<Song> _repoSong;
|
||||||
|
BaseRepository<Detail> _repoDetail;
|
||||||
|
SongRepository _repoSong2;
|
||||||
|
|
||||||
|
public SongService(BaseRepository<Song> repoSong, BaseRepository<Detail> repoDetail, SongRepository repoSong2)
|
||||||
|
{
|
||||||
|
_repoSong = repoSong;
|
||||||
|
_repoDetail = repoDetail;
|
||||||
|
_repoSong2 = repoSong2;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Transactional]
|
||||||
|
public virtual void Test()
|
||||||
|
{
|
||||||
|
_repoSong.Insert(new Song());
|
||||||
|
_repoDetail.Insert(new Detail());
|
||||||
|
_repoSong2.Insert(new Song());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SongRepository : DefaultRepository<Song, int>
|
||||||
|
{
|
||||||
|
public SongRepository(UnitOfWorkManager uowm) : base(uowm?.Orm, uowm) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Song
|
||||||
|
{
|
||||||
|
[Column(IsIdentity = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
}
|
||||||
|
public class Detail
|
||||||
|
{
|
||||||
|
[Column(IsIdentity = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public int SongId { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
}
|
||||||
|
}
|
27
Examples/aspnetcore_transaction/Program.cs
Normal file
27
Examples/aspnetcore_transaction/Program.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace aspnetcore_transaction
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
CreateHostBuilder(args).Build().Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||||
|
Host.CreateDefaultBuilder(args)
|
||||||
|
.ConfigureWebHostDefaults(webBuilder =>
|
||||||
|
{
|
||||||
|
webBuilder.UseStartup<Startup>();
|
||||||
|
})
|
||||||
|
.UseServiceProviderFactory(new FreeSql.DynamicProxyServiceProviderFactory());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:35350/",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dbcontext_01": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:35351/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
Examples/aspnetcore_transaction/Startup.cs
Normal file
58
Examples/aspnetcore_transaction/Startup.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using aspnetcore_transaction.Controllers;
|
||||||
|
using FreeSql;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.HttpsPolicy;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace aspnetcore_transaction
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public Startup(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
Configuration = configuration;
|
||||||
|
Fsql = new FreeSql.FreeSqlBuilder()
|
||||||
|
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\test_trans.db")
|
||||||
|
.UseAutoSyncStructure(true)
|
||||||
|
.UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText))
|
||||||
|
.UseNoneCommandParameter(true)
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IConfiguration Configuration { get; }
|
||||||
|
public static IFreeSql Fsql { get; private set; }
|
||||||
|
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddControllersWithViews();
|
||||||
|
|
||||||
|
services.AddSingleton<IFreeSql>(Fsql);
|
||||||
|
services.AddScoped<UnitOfWorkManager>();
|
||||||
|
services.AddFreeRepository(null, typeof(Startup).Assembly);
|
||||||
|
services.AddScoped<SongService>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||||
|
Console.OutputEncoding = Encoding.GetEncoding("GB2312");
|
||||||
|
Console.InputEncoding = Encoding.GetEncoding("GB2312");
|
||||||
|
|
||||||
|
app.UseHttpMethodOverride(new HttpMethodOverrideOptions { FormFieldName = "X-Http-Method-Override" });
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
app.UseRouting();
|
||||||
|
app.UseEndpoints(a => a.MapControllers());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
Examples/aspnetcore_transaction/TransactionalAttribute.cs
Normal file
51
Examples/aspnetcore_transaction/TransactionalAttribute.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
using FreeSql;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FreeSql
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 使用事务执行,请查看 Program.cs 代码开启动态代理
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
|
public class TransactionalAttribute : DynamicProxyAttribute, IActionFilter
|
||||||
|
{
|
||||||
|
public Propagation Propagation { get; set; } = Propagation.Requierd;
|
||||||
|
public IsolationLevel? IsolationLevel { get; set; }
|
||||||
|
|
||||||
|
[DynamicProxyFromServices]
|
||||||
|
UnitOfWorkManager _uowManager;
|
||||||
|
IUnitOfWork _uow;
|
||||||
|
|
||||||
|
public override Task Before(DynamicProxyBeforeArguments args) => OnBefore(_uowManager);
|
||||||
|
public override Task After(DynamicProxyAfterArguments args) => OnAfter(args.Exception);
|
||||||
|
|
||||||
|
//这里是为了 controller
|
||||||
|
public void OnActionExecuting(ActionExecutingContext context) => OnBefore(context.HttpContext.RequestServices.GetService(typeof(UnitOfWorkManager)) as UnitOfWorkManager);
|
||||||
|
public void OnActionExecuted(ActionExecutedContext context) => OnAfter(context.Exception);
|
||||||
|
|
||||||
|
|
||||||
|
Task OnBefore(UnitOfWorkManager uowm)
|
||||||
|
{
|
||||||
|
_uow = uowm.Begin(this.Propagation, this.IsolationLevel);
|
||||||
|
return Task.FromResult(false);
|
||||||
|
}
|
||||||
|
Task OnAfter(Exception ex)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (ex == null) _uow.Commit();
|
||||||
|
else _uow.Rollback();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_uow.Dispose();
|
||||||
|
}
|
||||||
|
return Task.FromResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FreeSql.DynamicProxy" Version="1.2.0" />
|
||||||
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\FreeSql.DbContext\FreeSql.DbContext.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -35,21 +35,21 @@ namespace FreeSql
|
|||||||
|
|
||||||
public ISelect<T1> Select<T1>() where T1 : class
|
public ISelect<T1> Select<T1>() where T1 : class
|
||||||
{
|
{
|
||||||
_resolveDbContext()?.FlushCommand();
|
_resolveDbContext?.Invoke()?.FlushCommand();
|
||||||
return _originalFsql.Select<T1>().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction(false));
|
return _originalFsql.Select<T1>().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction(false));
|
||||||
}
|
}
|
||||||
public ISelect<T1> Select<T1>(object dywhere) where T1 : class => Select<T1>().WhereDynamic(dywhere);
|
public ISelect<T1> Select<T1>(object dywhere) where T1 : class => Select<T1>().WhereDynamic(dywhere);
|
||||||
|
|
||||||
public IDelete<T1> Delete<T1>() where T1 : class
|
public IDelete<T1> Delete<T1>() where T1 : class
|
||||||
{
|
{
|
||||||
_resolveDbContext()?.FlushCommand();
|
_resolveDbContext?.Invoke()?.FlushCommand();
|
||||||
return _originalFsql.Delete<T1>().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction());
|
return _originalFsql.Delete<T1>().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction());
|
||||||
}
|
}
|
||||||
public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => Delete<T1>().WhereDynamic(dywhere);
|
public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => Delete<T1>().WhereDynamic(dywhere);
|
||||||
|
|
||||||
public IUpdate<T1> Update<T1>() where T1 : class
|
public IUpdate<T1> Update<T1>() where T1 : class
|
||||||
{
|
{
|
||||||
var db = _resolveDbContext();
|
var db = _resolveDbContext?.Invoke();
|
||||||
db?.FlushCommand();
|
db?.FlushCommand();
|
||||||
var update = _originalFsql.Update<T1>().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction());
|
var update = _originalFsql.Update<T1>().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction());
|
||||||
if (db?.Options.NoneParameter != null) update.NoneParameter(db.Options.NoneParameter.Value);
|
if (db?.Options.NoneParameter != null) update.NoneParameter(db.Options.NoneParameter.Value);
|
||||||
@ -59,7 +59,7 @@ namespace FreeSql
|
|||||||
|
|
||||||
public IInsert<T1> Insert<T1>() where T1 : class
|
public IInsert<T1> Insert<T1>() where T1 : class
|
||||||
{
|
{
|
||||||
var db = _resolveDbContext();
|
var db = _resolveDbContext?.Invoke();
|
||||||
db?.FlushCommand();
|
db?.FlushCommand();
|
||||||
var insert = _originalFsql.Insert<T1>().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction());
|
var insert = _originalFsql.Insert<T1>().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction());
|
||||||
if (db?.Options.NoneParameter != null) insert.NoneParameter(db.Options.NoneParameter.Value);
|
if (db?.Options.NoneParameter != null) insert.NoneParameter(db.Options.NoneParameter.Value);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<Authors>YeXiangQin</Authors>
|
<Authors>YeXiangQin</Authors>
|
||||||
<Description>FreeSql is the ORM in .NetCore, .NetFramework, And Xamarin. It supports Mysql, Postgresql, SqlServer, Oracle, Sqlite, Odbc, 达梦, And Access</Description>
|
<Description>FreeSql is the ORM in .NetCore, .NetFramework, And Xamarin. It supports Mysql, Postgresql, SqlServer, Oracle, Sqlite, Odbc, 达梦, And Access</Description>
|
||||||
<PackageProjectUrl>https://github.com/2881099/FreeSql.DbContext</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/2881099/FreeSql/wiki/DbContext</PackageProjectUrl>
|
||||||
<PackageTags>FreeSql ORM DbContext</PackageTags>
|
<PackageTags>FreeSql ORM DbContext</PackageTags>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
|
@ -227,41 +227,6 @@
|
|||||||
<param name="asTable">分表规则,参数:旧表名;返回:新表名 https://github.com/2881099/FreeSql/wiki/Repository</param>
|
<param name="asTable">分表规则,参数:旧表名;返回:新表名 https://github.com/2881099/FreeSql/wiki/Repository</param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="T:FreeSql.RepositoryUnitOfWorkManager">
|
|
||||||
<summary>
|
|
||||||
仓储的工作单元管理器
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:FreeSql.RepositoryUnitOfWorkManager.Propagation.Requierd">
|
|
||||||
<summary>
|
|
||||||
如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,默认的选择。
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:FreeSql.RepositoryUnitOfWorkManager.Propagation.Supports">
|
|
||||||
<summary>
|
|
||||||
支持当前事务,如果没有当前事务,就以非事务方法执行。
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:FreeSql.RepositoryUnitOfWorkManager.Propagation.Mandatory">
|
|
||||||
<summary>
|
|
||||||
使用当前事务,如果没有当前事务,就抛出异常。
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:FreeSql.RepositoryUnitOfWorkManager.Propagation.NotSupported">
|
|
||||||
<summary>
|
|
||||||
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:FreeSql.RepositoryUnitOfWorkManager.Propagation.Never">
|
|
||||||
<summary>
|
|
||||||
以非事务方式执行操作,如果当前事务存在则抛出异常。
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:FreeSql.RepositoryUnitOfWorkManager.Propagation.Nested">
|
|
||||||
<summary>
|
|
||||||
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,就新建一个事务。
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IDataFilter`1.Enable(System.String[])">
|
<member name="M:FreeSql.IDataFilter`1.Enable(System.String[])">
|
||||||
<summary>
|
<summary>
|
||||||
开启过滤器,若使用 using 则使用完后,恢复为原有状态
|
开启过滤器,若使用 using 则使用完后,恢复为原有状态
|
||||||
@ -381,6 +346,65 @@
|
|||||||
例如:20191121_214504_1
|
例如:20191121_214504_1
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="T:FreeSql.UnitOfWorkManager">
|
||||||
|
<summary>
|
||||||
|
工作单元管理器
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:FreeSql.UnitOfWorkManager.Current">
|
||||||
|
<summary>
|
||||||
|
当前的工作单元
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:FreeSql.UnitOfWorkManager.Binding(FreeSql.IBaseRepository)">
|
||||||
|
<summary>
|
||||||
|
将仓储的事务交给我管理
|
||||||
|
</summary>
|
||||||
|
<param name="repository"></param>
|
||||||
|
</member>
|
||||||
|
<member name="M:FreeSql.UnitOfWorkManager.Begin(FreeSql.Propagation,System.Nullable{System.Data.IsolationLevel})">
|
||||||
|
<summary>
|
||||||
|
创建工作单元
|
||||||
|
</summary>
|
||||||
|
<param name="propagation">事务传播方式</param>
|
||||||
|
<param name="isolationLevel">事务隔离级别</param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="T:FreeSql.Propagation">
|
||||||
|
<summary>
|
||||||
|
事务传播方式
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:FreeSql.Propagation.Requierd">
|
||||||
|
<summary>
|
||||||
|
如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,默认的选择。
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:FreeSql.Propagation.Supports">
|
||||||
|
<summary>
|
||||||
|
支持当前事务,如果没有当前事务,就以非事务方法执行。
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:FreeSql.Propagation.Mandatory">
|
||||||
|
<summary>
|
||||||
|
使用当前事务,如果没有当前事务,就抛出异常。
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:FreeSql.Propagation.NotSupported">
|
||||||
|
<summary>
|
||||||
|
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:FreeSql.Propagation.Never">
|
||||||
|
<summary>
|
||||||
|
以非事务方式执行操作,如果当前事务存在则抛出异常。
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:FreeSql.Propagation.Nested">
|
||||||
|
<summary>
|
||||||
|
以嵌套事务方式执行。
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="M:FreeSqlDbContextExtensions.Entity``1(FreeSql.ICodeFirst,System.Action{FreeSql.Extensions.EfCoreFluentApi.EfCoreTableFluent{``0}})">
|
<member name="M:FreeSqlDbContextExtensions.Entity``1(FreeSql.ICodeFirst,System.Action{FreeSql.Extensions.EfCoreFluentApi.EfCoreTableFluent{``0}})">
|
||||||
<summary>
|
<summary>
|
||||||
EFCore 95% 相似的 FluentApi 扩展方法
|
EFCore 95% 相似的 FluentApi 扩展方法
|
||||||
|
@ -1,201 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
|
||||||
using System.Data.Common;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace FreeSql
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 仓储的工作单元管理器
|
|
||||||
/// </summary>
|
|
||||||
public class RepositoryUnitOfWorkManager : IDisposable
|
|
||||||
{
|
|
||||||
IFreeSql _fsql;
|
|
||||||
List<IRepositoryUnitOfWork> _uows = new List<IRepositoryUnitOfWork>();
|
|
||||||
bool _isNotSupported = false;
|
|
||||||
|
|
||||||
public RepositoryUnitOfWorkManager(IFreeSql fsql)
|
|
||||||
{
|
|
||||||
_fsql = fsql ?? throw new ArgumentNullException($"{nameof(RepositoryUnitOfWorkManager)} 构造参数 {nameof(fsql)} 不能为 null");
|
|
||||||
}
|
|
||||||
|
|
||||||
~RepositoryUnitOfWorkManager() => this.Dispose();
|
|
||||||
int _disposeCounter;
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (Interlocked.Increment(ref _disposeCounter) != 1) return;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Exception exception = null;
|
|
||||||
for (var a = _uows.Count - 1; a >= 0; a--)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (exception == null) _uows[a].Commit();
|
|
||||||
else _uows[a].Rollback();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (exception == null) exception = ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (exception != null) throw exception;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_uows.Clear();
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Propagation
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,默认的选择。
|
|
||||||
/// </summary>
|
|
||||||
Requierd,
|
|
||||||
/// <summary>
|
|
||||||
/// 支持当前事务,如果没有当前事务,就以非事务方法执行。
|
|
||||||
/// </summary>
|
|
||||||
Supports,
|
|
||||||
/// <summary>
|
|
||||||
/// 使用当前事务,如果没有当前事务,就抛出异常。
|
|
||||||
/// </summary>
|
|
||||||
Mandatory,
|
|
||||||
/// <summary>
|
|
||||||
/// 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
|
|
||||||
/// </summary>
|
|
||||||
NotSupported,
|
|
||||||
/// <summary>
|
|
||||||
/// 以非事务方式执行操作,如果当前事务存在则抛出异常。
|
|
||||||
/// </summary>
|
|
||||||
Never,
|
|
||||||
/// <summary>
|
|
||||||
/// 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,就新建一个事务。
|
|
||||||
/// </summary>
|
|
||||||
Nested
|
|
||||||
}
|
|
||||||
|
|
||||||
public IRepositoryUnitOfWork Begin(Propagation propagation, IsolationLevel? isolationLevel = null)
|
|
||||||
{
|
|
||||||
if (propagation == Propagation.Requierd)
|
|
||||||
{
|
|
||||||
if (_isNotSupported == false)
|
|
||||||
{
|
|
||||||
for (var a = _uows.Count - 1; a >= 0; a--)
|
|
||||||
if (_uows[a].GetOrBeginTransaction(false) != null)
|
|
||||||
return new UnitOfWorkProxy(_uows[a]);
|
|
||||||
}
|
|
||||||
var uow = new RepositoryUnitOfWork(_fsql);
|
|
||||||
if (isolationLevel != null) uow.IsolationLevel = isolationLevel.Value;
|
|
||||||
try { uow.GetOrBeginTransaction(); }
|
|
||||||
catch { uow.Dispose(); throw; }
|
|
||||||
_uows.Add(uow);
|
|
||||||
return uow;
|
|
||||||
}
|
|
||||||
if (propagation == Propagation.Supports)
|
|
||||||
{
|
|
||||||
if (_isNotSupported == false)
|
|
||||||
{
|
|
||||||
for (var a = _uows.Count - 1; a >= 0; a--)
|
|
||||||
if (_uows[a].GetOrBeginTransaction(false) != null)
|
|
||||||
return new UnitOfWorkProxy(_uows[a]);
|
|
||||||
}
|
|
||||||
return new UnitOfWorkNothing(_fsql);
|
|
||||||
}
|
|
||||||
if (propagation == Propagation.Mandatory)
|
|
||||||
{
|
|
||||||
if (_isNotSupported == false)
|
|
||||||
{
|
|
||||||
for (var a = _uows.Count - 1; a >= 0; a--)
|
|
||||||
if (_uows[a].GetOrBeginTransaction(false) != null)
|
|
||||||
return new UnitOfWorkProxy(_uows[a]);
|
|
||||||
throw new Exception("Propagation_Mandatory: 使用当前事务,如果没有当前事务,就抛出异常");
|
|
||||||
}
|
|
||||||
throw new Exception("Propagation_Mandatory: 使用当前事务,如果没有当前事务,就抛出异常(NotSupported 事务挂起中)");
|
|
||||||
}
|
|
||||||
if (propagation == Propagation.NotSupported)
|
|
||||||
{
|
|
||||||
if (_isNotSupported == false)
|
|
||||||
{
|
|
||||||
_isNotSupported = true;
|
|
||||||
return new UnitOfWorkNothing(_fsql) { OnDispose = () => _isNotSupported = false };
|
|
||||||
}
|
|
||||||
return new UnitOfWorkNothing(_fsql);
|
|
||||||
}
|
|
||||||
if (propagation == Propagation.Never)
|
|
||||||
{
|
|
||||||
if (_isNotSupported == false)
|
|
||||||
{
|
|
||||||
for (var a = _uows.Count - 1; a >= 0; a--)
|
|
||||||
if (_uows[a].GetOrBeginTransaction(false) != null)
|
|
||||||
throw new Exception("Propagation_Never: 以非事务方式执行操作,如果当前事务存在则抛出异常");
|
|
||||||
}
|
|
||||||
return new UnitOfWorkNothing(_fsql);
|
|
||||||
}
|
|
||||||
if (propagation == Propagation.Nested)
|
|
||||||
{
|
|
||||||
var uow = new RepositoryUnitOfWork(_fsql);
|
|
||||||
if (isolationLevel != null) uow.IsolationLevel = isolationLevel.Value;
|
|
||||||
try { uow.GetOrBeginTransaction(); }
|
|
||||||
catch { uow.Dispose(); throw; }
|
|
||||||
_uows.Add(uow);
|
|
||||||
return uow;
|
|
||||||
}
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
class UnitOfWorkProxy : IRepositoryUnitOfWork
|
|
||||||
{
|
|
||||||
IRepositoryUnitOfWork _baseUow;
|
|
||||||
public UnitOfWorkProxy(IRepositoryUnitOfWork baseUow) => _baseUow = baseUow;
|
|
||||||
public IsolationLevel? IsolationLevel { get => _baseUow.IsolationLevel; set { } }
|
|
||||||
public DbContext.EntityChangeReport EntityChangeReport => _baseUow.EntityChangeReport;
|
|
||||||
|
|
||||||
public bool Enable => _baseUow.Enable;
|
|
||||||
public void Close() => _baseUow.Close();
|
|
||||||
public void Open() => _baseUow.Open();
|
|
||||||
|
|
||||||
public DbTransaction GetOrBeginTransaction(bool isCreate = true) => _baseUow.GetOrBeginTransaction(isCreate);
|
|
||||||
public void Commit() => this.Dispose();
|
|
||||||
public void Rollback() => _baseUow.Rollback();
|
|
||||||
public void Dispose() { }
|
|
||||||
|
|
||||||
public IBaseRepository<TEntity, TKey> GetRepository<TEntity, TKey>(Expression<Func<TEntity, bool>> filter = null) where TEntity : class => _baseUow.GetRepository<TEntity, TKey>(filter);
|
|
||||||
public IBaseRepository<TEntity> GetRepository<TEntity>(Expression<Func<TEntity, bool>> filter = null) where TEntity : class => _baseUow.GetRepository<TEntity>(filter);
|
|
||||||
public IBaseRepository<TEntity, Guid> GetGuidRepository<TEntity>(Expression<Func<TEntity, bool>> filter = null, Func<string, string> asTable = null) where TEntity : class => _baseUow.GetGuidRepository<TEntity>(filter);
|
|
||||||
}
|
|
||||||
class UnitOfWorkNothing : IRepositoryUnitOfWork
|
|
||||||
{
|
|
||||||
internal IFreeSql _fsql;
|
|
||||||
internal Action OnDispose;
|
|
||||||
public UnitOfWorkNothing(IFreeSql fsql) => _fsql = fsql;
|
|
||||||
public IsolationLevel? IsolationLevel { get; set; }
|
|
||||||
public DbContext.EntityChangeReport EntityChangeReport { get; } = new DbContext.EntityChangeReport();
|
|
||||||
|
|
||||||
public bool Enable { get; }
|
|
||||||
public void Close() { }
|
|
||||||
public void Open() { }
|
|
||||||
|
|
||||||
public DbTransaction GetOrBeginTransaction(bool isCreate = true) => null;
|
|
||||||
public void Commit()
|
|
||||||
{
|
|
||||||
if (EntityChangeReport != null && EntityChangeReport.OnChange != null && EntityChangeReport.Report.Any() == true)
|
|
||||||
EntityChangeReport.OnChange.Invoke(EntityChangeReport.Report);
|
|
||||||
this.Dispose();
|
|
||||||
}
|
|
||||||
public void Rollback() => this.Dispose();
|
|
||||||
public void Dispose() {
|
|
||||||
EntityChangeReport?.Report.Clear();
|
|
||||||
OnDispose?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IBaseRepository<TEntity, TKey> GetRepository<TEntity, TKey>(Expression<Func<TEntity, bool>> filter = null) where TEntity : class => new DefaultRepository<TEntity, TKey>(_fsql, filter);
|
|
||||||
public IBaseRepository<TEntity> GetRepository<TEntity>(Expression<Func<TEntity, bool>> filter = null) where TEntity : class => new DefaultRepository<TEntity, int>(_fsql, filter);
|
|
||||||
public IBaseRepository<TEntity, Guid> GetGuidRepository<TEntity>(Expression<Func<TEntity, bool>> filter = null, Func<string, string> asTable = null) where TEntity : class => new GuidRepository<TEntity>(_fsql, filter, asTable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,11 +7,19 @@ namespace FreeSql
|
|||||||
{
|
{
|
||||||
public DefaultRepository(IFreeSql fsql) : base(fsql, null, null) { }
|
public DefaultRepository(IFreeSql fsql) : base(fsql, null, null) { }
|
||||||
public DefaultRepository(IFreeSql fsql, Expression<Func<TEntity, bool>> filter) : base(fsql, filter, null) { }
|
public DefaultRepository(IFreeSql fsql, Expression<Func<TEntity, bool>> filter) : base(fsql, filter, null) { }
|
||||||
|
public DefaultRepository(IFreeSql fsql, UnitOfWorkManager uowManger) : base(uowManger?.Orm ?? fsql, null, null)
|
||||||
|
{
|
||||||
|
uowManger?.Binding(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GuidRepository<TEntity> : BaseRepository<TEntity, Guid> where TEntity : class
|
public class GuidRepository<TEntity> : BaseRepository<TEntity, Guid> where TEntity : class
|
||||||
{
|
{
|
||||||
public GuidRepository(IFreeSql fsql) : this(fsql, null, null) { }
|
public GuidRepository(IFreeSql fsql) : this(fsql, null, null) { }
|
||||||
public GuidRepository(IFreeSql fsql, Expression<Func<TEntity, bool>> filter, Func<string, string> asTable) : base(fsql, filter, asTable) { }
|
public GuidRepository(IFreeSql fsql, Expression<Func<TEntity, bool>> filter, Func<string, string> asTable) : base(fsql, filter, asTable) { }
|
||||||
|
public GuidRepository(IFreeSql fsql, UnitOfWorkManager uowManger) : base(uowManger?.Orm ?? fsql, null, null)
|
||||||
|
{
|
||||||
|
uowManger?.Binding(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
274
FreeSql.DbContext/UnitOfWork/UnitOfWorkManager.cs
Normal file
274
FreeSql.DbContext/UnitOfWork/UnitOfWorkManager.cs
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace FreeSql
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 工作单元管理器
|
||||||
|
/// </summary>
|
||||||
|
public class UnitOfWorkManager : IDisposable
|
||||||
|
{
|
||||||
|
DbContextScopedFreeSql _ormScoped;
|
||||||
|
public IFreeSql Orm => _ormScoped;
|
||||||
|
List<UowInfo> _rawUows = new List<UowInfo>();
|
||||||
|
List<UowInfo> _allUows = new List<UowInfo>();
|
||||||
|
List<RepoInfo> _repos = new List<RepoInfo>();
|
||||||
|
|
||||||
|
public UnitOfWorkManager(IFreeSql fsql)
|
||||||
|
{
|
||||||
|
if (fsql == null) throw new ArgumentNullException($"{nameof(UnitOfWorkManager)} 构造参数 {nameof(fsql)} 不能为 null");
|
||||||
|
_ormScoped = DbContextScopedFreeSql.Create(fsql, null, () => this.Current);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Dispose
|
||||||
|
~UnitOfWorkManager() => this.Dispose();
|
||||||
|
int _disposeCounter;
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (Interlocked.Increment(ref _disposeCounter) != 1) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Exception exception = null;
|
||||||
|
for (var a = _rawUows.Count - 1; a >= 0; a--)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (exception == null) _rawUows[a].Uow.Commit();
|
||||||
|
else _rawUows[a].Uow.Rollback();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (exception == null) exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exception != null) throw exception;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_rawUows.Clear();
|
||||||
|
_allUows.Clear();
|
||||||
|
_repos.Clear();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前的工作单元
|
||||||
|
/// </summary>
|
||||||
|
public IUnitOfWork Current => _allUows.LastOrDefault()?.Uow;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将仓储的事务交给我管理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repository"></param>
|
||||||
|
public void Binding(IBaseRepository repository)
|
||||||
|
{
|
||||||
|
var repoInfo = new RepoInfo(repository);
|
||||||
|
repository.UnitOfWork = Current;
|
||||||
|
_repos.Add(repoInfo);
|
||||||
|
}
|
||||||
|
void SetAllRepositoryUow()
|
||||||
|
{
|
||||||
|
foreach (var repo in _repos)
|
||||||
|
repo.Repository.UnitOfWork = Current ?? repo.OrginalUow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建工作单元
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="propagation">事务传播方式</param>
|
||||||
|
/// <param name="isolationLevel">事务隔离级别</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public IUnitOfWork Begin(Propagation propagation = Propagation.Requierd, IsolationLevel? isolationLevel = null)
|
||||||
|
{
|
||||||
|
switch (propagation)
|
||||||
|
{
|
||||||
|
case Propagation.Requierd: return FindedUowCreateVirtual() ?? CreateUow(isolationLevel);
|
||||||
|
case Propagation.Supports: return FindedUowCreateVirtual() ?? CreateUowNothing(_allUows.LastOrDefault()?.IsNotSupported ?? false);
|
||||||
|
case Propagation.Mandatory: return FindedUowCreateVirtual() ?? throw new Exception("Propagation_Mandatory: 使用当前事务,如果没有当前事务,就抛出异常");
|
||||||
|
case Propagation.NotSupported: return CreateUowNothing(true);
|
||||||
|
case Propagation.Never:
|
||||||
|
var isNotSupported = _allUows.LastOrDefault()?.IsNotSupported ?? false;
|
||||||
|
if (isNotSupported == false)
|
||||||
|
{
|
||||||
|
for (var a = _rawUows.Count - 1; a >= 0; a--)
|
||||||
|
if (_rawUows[a].Uow.GetOrBeginTransaction(false) != null)
|
||||||
|
throw new Exception("Propagation_Never: 以非事务方式执行操作,如果当前事务存在则抛出异常");
|
||||||
|
}
|
||||||
|
return CreateUowNothing(isNotSupported);
|
||||||
|
case Propagation.Nested: return CreateUow(isolationLevel);
|
||||||
|
default: throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IUnitOfWork FindedUowCreateVirtual()
|
||||||
|
{
|
||||||
|
var isNotSupported = _allUows.LastOrDefault()?.IsNotSupported ?? false;
|
||||||
|
if (isNotSupported == false)
|
||||||
|
{
|
||||||
|
for (var a = _rawUows.Count - 1; a >= 0; a--)
|
||||||
|
if (_rawUows[a].Uow.GetOrBeginTransaction(false) != null)
|
||||||
|
{
|
||||||
|
var uow = new UnitOfWorkVirtual(_rawUows[a].Uow);
|
||||||
|
var uowInfo = new UowInfo(uow, UowInfo.UowType.Virtual, isNotSupported);
|
||||||
|
uow.OnDispose = () => _allUows.Remove(uowInfo);
|
||||||
|
_allUows.Add(uowInfo);
|
||||||
|
SetAllRepositoryUow();
|
||||||
|
return uow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
IUnitOfWork CreateUowNothing(bool isNotSupported)
|
||||||
|
{
|
||||||
|
var uow = new UnitOfWorkNothing(Orm);
|
||||||
|
var uowInfo = new UowInfo(uow, UowInfo.UowType.Nothing, isNotSupported);
|
||||||
|
uow.OnDispose = () => _allUows.Remove(uowInfo);
|
||||||
|
_allUows.Add(uowInfo);
|
||||||
|
SetAllRepositoryUow();
|
||||||
|
return uow;
|
||||||
|
}
|
||||||
|
IUnitOfWork CreateUow(IsolationLevel? isolationLevel)
|
||||||
|
{
|
||||||
|
var uow = new UnitOfWorkOrginal(new UnitOfWork(Orm));
|
||||||
|
var uowInfo = new UowInfo(uow, UowInfo.UowType.Orginal, false);
|
||||||
|
if (isolationLevel != null) uow.IsolationLevel = isolationLevel.Value;
|
||||||
|
try { uow.GetOrBeginTransaction(); }
|
||||||
|
catch { uow.Dispose(); throw; }
|
||||||
|
|
||||||
|
uow.OnDispose = () =>
|
||||||
|
{
|
||||||
|
_rawUows.Remove(uowInfo);
|
||||||
|
_allUows.Remove(uowInfo);
|
||||||
|
SetAllRepositoryUow();
|
||||||
|
};
|
||||||
|
_rawUows.Add(uowInfo);
|
||||||
|
_allUows.Add(uowInfo);
|
||||||
|
SetAllRepositoryUow();
|
||||||
|
return uow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RepoInfo
|
||||||
|
{
|
||||||
|
public IBaseRepository Repository;
|
||||||
|
public IUnitOfWork OrginalUow;
|
||||||
|
|
||||||
|
public RepoInfo(IBaseRepository repository)
|
||||||
|
{
|
||||||
|
this.Repository = repository;
|
||||||
|
this.OrginalUow = repository.UnitOfWork;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class UowInfo
|
||||||
|
{
|
||||||
|
public IUnitOfWork Uow;
|
||||||
|
public UowType Type;
|
||||||
|
public bool IsNotSupported;
|
||||||
|
public enum UowType { Orginal, Virtual, Nothing }
|
||||||
|
|
||||||
|
public UowInfo(IUnitOfWork uow, UowType type, bool isNotSupported)
|
||||||
|
{
|
||||||
|
this.Uow = uow;
|
||||||
|
this.Type = type;
|
||||||
|
this.IsNotSupported = isNotSupported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class UnitOfWorkOrginal : IUnitOfWork
|
||||||
|
{
|
||||||
|
IUnitOfWork _baseUow;
|
||||||
|
internal Action OnDispose;
|
||||||
|
public UnitOfWorkOrginal(IUnitOfWork baseUow) => _baseUow = baseUow;
|
||||||
|
public IsolationLevel? IsolationLevel { get => _baseUow.IsolationLevel; set => _baseUow.IsolationLevel = value; }
|
||||||
|
public DbContext.EntityChangeReport EntityChangeReport => _baseUow.EntityChangeReport;
|
||||||
|
|
||||||
|
public bool Enable => _baseUow.Enable;
|
||||||
|
public void Close() => _baseUow.Close();
|
||||||
|
public void Open() => _baseUow.Open();
|
||||||
|
|
||||||
|
public DbTransaction GetOrBeginTransaction(bool isCreate = true) => _baseUow.GetOrBeginTransaction(isCreate);
|
||||||
|
public void Commit() => _baseUow.Commit();
|
||||||
|
public void Rollback() => _baseUow.Rollback();
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_baseUow.Dispose();
|
||||||
|
OnDispose?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class UnitOfWorkVirtual : IUnitOfWork
|
||||||
|
{
|
||||||
|
IUnitOfWork _baseUow;
|
||||||
|
internal Action OnDispose;
|
||||||
|
public UnitOfWorkVirtual(IUnitOfWork baseUow) => _baseUow = baseUow;
|
||||||
|
public IsolationLevel? IsolationLevel { get => _baseUow.IsolationLevel; set { } }
|
||||||
|
public DbContext.EntityChangeReport EntityChangeReport => _baseUow.EntityChangeReport;
|
||||||
|
|
||||||
|
public bool Enable => _baseUow.Enable;
|
||||||
|
public void Close() => _baseUow.Close();
|
||||||
|
public void Open() => _baseUow.Open();
|
||||||
|
|
||||||
|
public DbTransaction GetOrBeginTransaction(bool isCreate = true) => _baseUow.GetOrBeginTransaction(isCreate);
|
||||||
|
public void Commit() { }
|
||||||
|
public void Rollback() => _baseUow.Rollback();
|
||||||
|
public void Dispose() => OnDispose?.Invoke();
|
||||||
|
}
|
||||||
|
class UnitOfWorkNothing : IUnitOfWork
|
||||||
|
{
|
||||||
|
internal IFreeSql _fsql;
|
||||||
|
internal Action OnDispose;
|
||||||
|
public UnitOfWorkNothing(IFreeSql fsql) => _fsql = fsql;
|
||||||
|
public IsolationLevel? IsolationLevel { get; set; }
|
||||||
|
public DbContext.EntityChangeReport EntityChangeReport { get; } = new DbContext.EntityChangeReport();
|
||||||
|
|
||||||
|
public bool Enable { get; }
|
||||||
|
public void Close() { }
|
||||||
|
public void Open() { }
|
||||||
|
|
||||||
|
public DbTransaction GetOrBeginTransaction(bool isCreate = true) => null;
|
||||||
|
public void Commit()
|
||||||
|
{
|
||||||
|
if (EntityChangeReport != null && EntityChangeReport.OnChange != null && EntityChangeReport.Report.Any() == true)
|
||||||
|
EntityChangeReport.OnChange.Invoke(EntityChangeReport.Report);
|
||||||
|
EntityChangeReport?.Report.Clear();
|
||||||
|
}
|
||||||
|
public void Rollback() => EntityChangeReport?.Report.Clear();
|
||||||
|
public void Dispose() => OnDispose?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 事务传播方式
|
||||||
|
/// </summary>
|
||||||
|
public enum Propagation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,默认的选择。
|
||||||
|
/// </summary>
|
||||||
|
Requierd,
|
||||||
|
/// <summary>
|
||||||
|
/// 支持当前事务,如果没有当前事务,就以非事务方法执行。
|
||||||
|
/// </summary>
|
||||||
|
Supports,
|
||||||
|
/// <summary>
|
||||||
|
/// 使用当前事务,如果没有当前事务,就抛出异常。
|
||||||
|
/// </summary>
|
||||||
|
Mandatory,
|
||||||
|
/// <summary>
|
||||||
|
/// 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
|
||||||
|
/// </summary>
|
||||||
|
NotSupported,
|
||||||
|
/// <summary>
|
||||||
|
/// 以非事务方式执行操作,如果当前事务存在则抛出异常。
|
||||||
|
/// </summary>
|
||||||
|
Never,
|
||||||
|
/// <summary>
|
||||||
|
/// 以嵌套事务方式执行。
|
||||||
|
/// </summary>
|
||||||
|
Nested
|
||||||
|
}
|
||||||
|
}
|
15
FreeSql.sln
15
FreeSql.sln
@ -78,6 +78,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.Linq", "
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.Dameng", "Providers\FreeSql.Provider.Dameng\FreeSql.Provider.Dameng.csproj", "{E74D90E8-1CBC-4677-817B-1CA05AB97937}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.Dameng", "Providers\FreeSql.Provider.Dameng\FreeSql.Provider.Dameng.csproj", "{E74D90E8-1CBC-4677-817B-1CA05AB97937}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "aspnetcore_transaction", "Examples\aspnetcore_transaction\aspnetcore_transaction.csproj", "{07AB0B37-A8B1-4FB1-9259-7B804E369E36}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -472,6 +474,18 @@ Global
|
|||||||
{E74D90E8-1CBC-4677-817B-1CA05AB97937}.Release|x64.Build.0 = Release|Any CPU
|
{E74D90E8-1CBC-4677-817B-1CA05AB97937}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{E74D90E8-1CBC-4677-817B-1CA05AB97937}.Release|x86.ActiveCfg = Release|Any CPU
|
{E74D90E8-1CBC-4677-817B-1CA05AB97937}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{E74D90E8-1CBC-4677-817B-1CA05AB97937}.Release|x86.Build.0 = Release|Any CPU
|
{E74D90E8-1CBC-4677-817B-1CA05AB97937}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -499,6 +513,7 @@ Global
|
|||||||
{B397A761-F646-41CF-A160-AB6C05DAF2FB} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
|
{B397A761-F646-41CF-A160-AB6C05DAF2FB} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
|
||||||
{57B3F5B0-D46A-4442-8EC6-9A9A784404B7} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA}
|
{57B3F5B0-D46A-4442-8EC6-9A9A784404B7} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA}
|
||||||
{E74D90E8-1CBC-4677-817B-1CA05AB97937} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
|
{E74D90E8-1CBC-4677-817B-1CA05AB97937} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
|
||||||
|
{07AB0B37-A8B1-4FB1-9259-7B804E369E36} = {94C8A78D-AA15-47B2-A348-530CD86BFC1B}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}
|
SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}
|
||||||
|
@ -2310,137 +2310,6 @@
|
|||||||
<param name="parms"></param>
|
<param name="parms"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FreeSql.IAdo.ExecuteReaderAsync(System.Func{System.Data.Common.DbDataReader,System.Threading.Tasks.Task},System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
|
|
||||||
<summary>
|
|
||||||
查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
|
|
||||||
</summary>
|
|
||||||
<param name="readerHander"></param>
|
|
||||||
<param name="cmdType"></param>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="cmdParms"></param>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.ExecuteReaderAsync(System.Func{System.Data.Common.DbDataReader,System.Threading.Tasks.Task},System.String,System.Object)">
|
|
||||||
<summary>
|
|
||||||
查询,ExecuteReaderAsync(dr => {}, "select * from user where age > ?age", new { age = 25 })
|
|
||||||
</summary>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="parms"></param>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.ExecuteArrayAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
|
|
||||||
<summary>
|
|
||||||
查询
|
|
||||||
</summary>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="cmdParms"></param>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.ExecuteArrayAsync(System.String,System.Object)">
|
|
||||||
<summary>
|
|
||||||
查询,ExecuteArrayAsync("select * from user where age > ?age", new { age = 25 })
|
|
||||||
</summary>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="parms"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.ExecuteDataSetAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
|
|
||||||
<summary>
|
|
||||||
查询
|
|
||||||
</summary>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="cmdParms"></param>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.ExecuteDataSetAsync(System.String,System.Object)">
|
|
||||||
<summary>
|
|
||||||
查询,ExecuteDataSetAsync("select * from user where age > ?age; select 2", new { age = 25 })
|
|
||||||
</summary>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="parms"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.ExecuteDataTableAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
|
|
||||||
<summary>
|
|
||||||
查询
|
|
||||||
</summary>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="cmdParms"></param>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.ExecuteDataTableAsync(System.String,System.Object)">
|
|
||||||
<summary>
|
|
||||||
查询,ExecuteDataTableAsync("select * from user where age > ?age", new { age = 25 })
|
|
||||||
</summary>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="parms"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.ExecuteNonQueryAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
|
|
||||||
<summary>
|
|
||||||
在【主库】执行
|
|
||||||
</summary>
|
|
||||||
<param name="cmdType"></param>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="cmdParms"></param>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.ExecuteNonQueryAsync(System.String,System.Object)">
|
|
||||||
<summary>
|
|
||||||
在【主库】执行,ExecuteNonQueryAsync("delete from user where age > ?age", new { age = 25 })
|
|
||||||
</summary>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="parms"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.ExecuteScalarAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
|
|
||||||
<summary>
|
|
||||||
在【主库】执行
|
|
||||||
</summary>
|
|
||||||
<param name="cmdType"></param>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="cmdParms"></param>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.ExecuteScalarAsync(System.String,System.Object)">
|
|
||||||
<summary>
|
|
||||||
在【主库】执行,ExecuteScalarAsync("select 1 from user where age > ?age", new { age = 25 })
|
|
||||||
</summary>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="parms"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.QueryAsync``1(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
|
|
||||||
<summary>
|
|
||||||
执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new SqlParameter { ParameterName = "age", Value = 25 })
|
|
||||||
</summary>
|
|
||||||
<typeparam name="T"></typeparam>
|
|
||||||
<param name="cmdType"></param>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="cmdParms"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.QueryAsync``1(System.String,System.Object)">
|
|
||||||
<summary>
|
|
||||||
执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new { age = 25 })
|
|
||||||
</summary>
|
|
||||||
<typeparam name="T"></typeparam>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="parms"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.QueryAsync``2(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
|
|
||||||
<summary>
|
|
||||||
执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 })
|
|
||||||
</summary>
|
|
||||||
<typeparam name="T1"></typeparam>
|
|
||||||
<param name="cmdType"></param>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="cmdParms"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IAdo.QueryAsync``2(System.String,System.Object)">
|
|
||||||
<summary>
|
|
||||||
执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new { age = 25 })
|
|
||||||
</summary>
|
|
||||||
<typeparam name="T1"></typeparam>
|
|
||||||
<param name="cmdText"></param>
|
|
||||||
<param name="parms"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="E:FreeSql.IAop.ParseExpression">
|
<member name="E:FreeSql.IAop.ParseExpression">
|
||||||
<summary>
|
<summary>
|
||||||
可自定义解析表达式
|
可自定义解析表达式
|
||||||
@ -2961,12 +2830,6 @@
|
|||||||
<param name="timeout">超时</param>
|
<param name="timeout">超时</param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FreeSql.Internal.ObjectPool.IObjectPool`1.GetAsync">
|
|
||||||
<summary>
|
|
||||||
获取资源
|
|
||||||
</summary>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.Internal.ObjectPool.IObjectPool`1.Return(FreeSql.Internal.ObjectPool.Object{`0},System.Boolean)">
|
<member name="M:FreeSql.Internal.ObjectPool.IObjectPool`1.Return(FreeSql.Internal.ObjectPool.Object{`0},System.Boolean)">
|
||||||
<summary>
|
<summary>
|
||||||
使用完毕后,归还资源
|
使用完毕后,归还资源
|
||||||
@ -3037,12 +2900,6 @@
|
|||||||
</summary>
|
</summary>
|
||||||
<param name="obj">资源对象</param>
|
<param name="obj">资源对象</param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FreeSql.Internal.ObjectPool.IPolicy`1.OnGetAsync(FreeSql.Internal.ObjectPool.Object{`0})">
|
|
||||||
<summary>
|
|
||||||
从对象池获取对象成功的时候触发,通过该方法统计或初始化对象
|
|
||||||
</summary>
|
|
||||||
<param name="obj">资源对象</param>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.Internal.ObjectPool.IPolicy`1.OnReturn(FreeSql.Internal.ObjectPool.Object{`0})">
|
<member name="M:FreeSql.Internal.ObjectPool.IPolicy`1.OnReturn(FreeSql.Internal.ObjectPool.Object{`0})">
|
||||||
<summary>
|
<summary>
|
||||||
归还对象给对象池的时候触发
|
归还对象给对象池的时候触发
|
||||||
|
@ -16,14 +16,14 @@ namespace FreeSql.Internal.CommonProvider
|
|||||||
class Transaction2
|
class Transaction2
|
||||||
{
|
{
|
||||||
internal Aop.TraceBeforeEventArgs AopBefore;
|
internal Aop.TraceBeforeEventArgs AopBefore;
|
||||||
internal Object<DbConnection> Conn;
|
internal Object<DbConnection> Connection;
|
||||||
internal DbTransaction Transaction;
|
internal DbTransaction Transaction;
|
||||||
internal DateTime RunTime;
|
internal DateTime RunTime;
|
||||||
internal TimeSpan Timeout;
|
internal TimeSpan Timeout;
|
||||||
|
|
||||||
public Transaction2(Object<DbConnection> conn, DbTransaction tran, TimeSpan timeout)
|
public Transaction2(Object<DbConnection> conn, DbTransaction tran, TimeSpan timeout)
|
||||||
{
|
{
|
||||||
Conn = conn;
|
Connection = conn;
|
||||||
Transaction = tran;
|
Transaction = tran;
|
||||||
RunTime = DateTime.Now;
|
RunTime = DateTime.Now;
|
||||||
Timeout = timeout;
|
Timeout = timeout;
|
||||||
@ -31,7 +31,6 @@ namespace FreeSql.Internal.CommonProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ConcurrentDictionary<int, Transaction2> _trans = new ConcurrentDictionary<int, Transaction2>();
|
private ConcurrentDictionary<int, Transaction2> _trans = new ConcurrentDictionary<int, Transaction2>();
|
||||||
private object _trans_lock = new object();
|
|
||||||
|
|
||||||
public DbTransaction TransactionCurrentThread => _trans.TryGetValue(Thread.CurrentThread.ManagedThreadId, out var conn) && conn.Transaction?.Connection != null ? conn.Transaction : null;
|
public DbTransaction TransactionCurrentThread => _trans.TryGetValue(Thread.CurrentThread.ManagedThreadId, out var conn) && conn.Transaction?.Connection != null ? conn.Transaction : null;
|
||||||
public Aop.TraceBeforeEventArgs TransactionCurrentThreadAopBefore => _trans.TryGetValue(Thread.CurrentThread.ManagedThreadId, out var conn) && conn.Transaction?.Connection != null ? conn.AopBefore : null;
|
public Aop.TraceBeforeEventArgs TransactionCurrentThreadAopBefore => _trans.TryGetValue(Thread.CurrentThread.ManagedThreadId, out var conn) && conn.Transaction?.Connection != null ? conn.AopBefore : null;
|
||||||
@ -61,35 +60,27 @@ namespace FreeSql.Internal.CommonProvider
|
|||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
if (_trans.ContainsKey(tid)) CommitTransaction();
|
if (_trans.ContainsKey(tid)) CommitTransaction();
|
||||||
|
_trans.TryAdd(tid, tran);
|
||||||
lock (_trans_lock)
|
|
||||||
_trans.TryAdd(tid, tran);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CommitTimeoutTransaction()
|
private void CommitTimeoutTransaction()
|
||||||
{
|
{
|
||||||
if (_trans.Count > 0)
|
if (_trans.Count > 0)
|
||||||
{
|
{
|
||||||
Transaction2[] trans = null;
|
var trans = _trans.Values.Where(st2 => DateTime.Now.Subtract(st2.RunTime) > st2.Timeout).ToArray();
|
||||||
lock (_trans_lock)
|
foreach (var tran in trans) CommitTransaction(true, tran, null, "Timeout自动提交");
|
||||||
trans = _trans.Values.Where(st2 => DateTime.Now.Subtract(st2.RunTime) > st2.Timeout).ToArray();
|
|
||||||
foreach (Transaction2 tran in trans) CommitTransaction(true, tran, null, "Timeout自动提交");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void CommitTransaction(bool isCommit, Transaction2 tran, Exception rollbackException, string remark = null)
|
private void CommitTransaction(bool isCommit, Transaction2 tran, Exception rollbackException, string remark = null)
|
||||||
{
|
{
|
||||||
if (tran == null || tran.Transaction == null || tran.Transaction.Connection == null) return;
|
if (tran == null || tran.Transaction == null || tran.Transaction.Connection == null) return;
|
||||||
|
_trans.TryRemove(tran.Connection.LastGetThreadId, out var oldtran);
|
||||||
if (_trans.ContainsKey(tran.Conn.LastGetThreadId))
|
|
||||||
lock (_trans_lock)
|
|
||||||
if (_trans.ContainsKey(tran.Conn.LastGetThreadId))
|
|
||||||
_trans.TryRemove(tran.Conn.LastGetThreadId, out var oldtran);
|
|
||||||
|
|
||||||
Exception ex = null;
|
Exception ex = null;
|
||||||
if (string.IsNullOrEmpty(remark)) remark = isCommit ? "提交" : "回滚";
|
if (string.IsNullOrEmpty(remark)) remark = isCommit ? "提交" : "回滚";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Trace.WriteLine($"线程{tran.Conn.LastGetThreadId}事务{remark}");
|
Trace.WriteLine($"线程{tran.Connection.LastGetThreadId}事务{remark}");
|
||||||
if (isCommit) tran.Transaction.Commit();
|
if (isCommit) tran.Transaction.Commit();
|
||||||
else tran.Transaction.Rollback();
|
else tran.Transaction.Rollback();
|
||||||
}
|
}
|
||||||
@ -100,7 +91,7 @@ namespace FreeSql.Internal.CommonProvider
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
ReturnConnection(MasterPool, tran.Conn, ex); //MasterPool.Return(tran.Conn, ex);
|
ReturnConnection(MasterPool, tran.Connection, ex); //MasterPool.Return(tran.Conn, ex);
|
||||||
|
|
||||||
var after = new Aop.TraceAfterEventArgs(tran.AopBefore, remark, ex ?? rollbackException);
|
var after = new Aop.TraceAfterEventArgs(tran.AopBefore, remark, ex ?? rollbackException);
|
||||||
_util?._orm?.Aop.TraceAfterHandler?.Invoke(this, after);
|
_util?._orm?.Aop.TraceAfterHandler?.Invoke(this, after);
|
||||||
@ -141,10 +132,8 @@ namespace FreeSql.Internal.CommonProvider
|
|||||||
if (Interlocked.Increment(ref _disposeCounter) != 1) return;
|
if (Interlocked.Increment(ref _disposeCounter) != 1) return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Transaction2[] trans = null;
|
var trans = _trans.Values.ToArray();
|
||||||
lock (_trans_lock)
|
foreach (var tran in trans) CommitTransaction(false, tran, null, "Dispose自动提交");
|
||||||
trans = _trans.Values.ToArray();
|
|
||||||
foreach (Transaction2 tran in trans) CommitTransaction(false, tran, null, "Dispose自动提交");
|
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user