DotNetNext / SqlSugar

.Net aot ORM Fastest ORM Simple Easy VB.NET Sqlite orm Oracle ORM Mysql Orm 虚谷数据库 postgresql ORm SqlServer oRm 达梦 ORM 人大金仓 ORM 神通ORM C# ORM , C# ORM .NET ORM NET5 ORM .NET6 ORM ClickHouse orm QuestDb ,TDengine ORM,OceanBase orm,GaussDB orm ,Tidb orm Object/Relational Mapping
https://www.donet5.com/Home/Doc
MIT License
5.19k stars 1.32k forks source link

如何在 SqlSugar 中集成 CAP #1207

Closed yang-xiaodong closed 7 months ago

yang-xiaodong commented 7 months ago

背景描述

有朋友咨询(前同事)关于CAP如何和SqlSugar集成的问题,在SqlSugar文档章节 CAP事务 TCC和Saga 已经有相关描述。

本 Issue 提供一种简便的通过扩展方法来实现这一点,本思路同样适用于其他三方ORM.

在 CAP 中,事务对象需要交给CAP进行提交从而在事务实现提交后对缓存消息到 Broker 的 Flush 动作,而目前的Orm大部分都有自己的事务管理对象进行事务的提交。

CAP官方直接原生支持使用 ADO.NET 和 EntityFrameworkCore 进行事务集成,而对于第三方ORM则需要自行扩展,以下为 SqlSugar 和 CAP 的 集成示例。

定义扩展类

CapTransactionBase 为CAP封装的事务抽象对象,用于对事务进行代理提交,可通过扩展此类来达到事务提交后的消息推送目的。

public class SqlSugarTransaction : CapTransactionBase
{
    public SqlSugarTransaction(IDispatcher dispatcher, IAdo ado) : base(dispatcher)
    {
        Ado = ado;
        DbTransaction = ado.Transaction;
    }

    public IAdo Ado { get; set; }

    public override void Commit()
    {
        Ado.CommitTran();
        Flush();
    }

    public override async Task CommitAsync(CancellationToken cancellationToken = default)
    {
        await Ado.CommitTranAsync();
        Flush();
    }

    public override void Dispose()
    {
        Ado.Dispose();
    }

    public override void Rollback()
    {
        Ado.RollbackTran();
    }

    public override async Task RollbackAsync(CancellationToken cancellationToken = default)
    {
        await Ado.RollbackTranAsync();
    }
}

使用扩展方法基于 ISqlSugarClient 对象扩展,同样也可SqlSugar提供基于 IAdo 对象扩展,由于 AsyncLocal 的问题,目前不支持异步。

public static class Extensions
{
    public static ICapTransaction BeginCapTransaction(this ISqlSugarClient sugarClient, ICapPublisher publisher, bool autoCommit = false)
    {
        var dispatcher = publisher.ServiceProvider.GetRequiredService<IDispatcher>();
        sugarClient.Ado.BeginTran();
        var transaction = new SqlSugarTransaction(dispatcher, sugarClient.Ado)
        {
            AutoCommit = autoCommit
        }; 
        return publisher.Transaction.Value = transaction;
    }
}

示例

封装完成后,发送事务集成消息变得更加简单。

场景一表示在执行了系列业务操作后,才进行消息发送,此时支持自动提交事务。

场景二表示先进行消息发送,才执行业务操作,此时不能使用自动提交事务,否则发完消息后CAP会立即提交事务。

[HttpGet("test")]
public IActionResult PublishWithSqlSugarTrans([FromServices] ISqlSugarClient sqlSugar, [FromServices] ICapPublisher cap)
{
    //场景一 : 发布消息在业务代码后
    using (var trans = sqlSugar.BeginCapTransaction(cap, autoCommit: true))
    {
        try
        {
            sqlSugar.Insertable(new Persons() { Name = "jack" }).ExecuteCommand();
            //throw new Exception("error"); //throw a exception to test transaction is work
            cap.Publish("sample.rabbitmq.sqlsugar", DateTime.Now);  //发布消息在业务代码后
        }
        catch (Exception)
        {
            trans.Rollback();
        }
    }

    //场景二:发布消息在业务代码前,不能使用自动提交,否则发完消息后CAP会立即提交事务。 autoCommit must be false
    using (var trans = sqlSugar.BeginCapTransaction(cap, autoCommit: false))
    {
        try
        {
            cap.Publish("sample.rabbitmq.sqlsugar", DateTime.Now);
            throw new Exception("error"); //throw a exception to test transaction is work
            sqlSugar.Insertable(new Persons() { Name = "tom" }).ExecuteCommand();
            trans.Commit();
        }
        catch (Exception)
        {
            trans.Rollback();
        }
    }
    return Ok();
}
yang-xiaodong commented 7 months ago

由于这是一篇帮助说明文章,用于提供搜索。作者可以选择是否同步到SqlSugar文档或者同步到 www.donet5.com 的问题列表中。

现在关闭 Issue.

DotNetNext commented 7 months ago

好的

DotNetNext commented 7 months ago

https://www.donet5.com/Ask/9/23459 文档加了连接也备份了一下,如果有新的修改可以在这个贴子下回复