创建一个相同上下文共享的 数据库操作对象
//注册上下文:AOP里面可以获取IOC对象,如果有现成框架比如Furion可以不写这一行 services.AddHttpContextAccessor(); //注册SqlSugar services.AddSingleton<ISqlSugarClient>(s => { //单例不要写在泛型类中, 类<T>.Db 这种是无效单例 ,T不同就会有多个实例 SqlSugarScope Db= new SqlSugarScope (new List<ConnectionConfig>() { new ConnectionConfig(){ConfigId="0",DbType=DbType.SqlServer,....}, new ConnectionConfig(){ConfigId="1",DbType=DbType.MySql,.....} //ConfigId用来区别是哪个库 } , db=> { //如果是GetConnectionScope或者GetConnectionScopeWithAttr这边也应该是GetConnectionScope //如果用的是GetConnection或者GetConnectionWithAttr这边也应该是GetConnection //用哪个就AOP添加哪个 //技巧:这边可以循环处理这个更方便些 db.GetConnection("0").Aop.OnLogExecuting = (sql, p) => { Console.WriteLine(sql); }; db.GetConnection("1").Aop.OnLogExecuting = (sql, p) => { Console.WriteLine(sql); }; //获取IOC对象不要求在一个上下文 //vra log=s.GetService<Log>() //获取IOC对象要求在一个上下文 //var appServive = s.GetService<IHttpContextAccessor>(); //var log= appServive?.HttpContext?.RequestServices.GetService<Log>(); }); return Db; });
注意:仓储对象不能单例注入
每个GetConnection出来的数据库是独立的数据库操作对象,可以一起使用相互没有任何影响
//方式1:通过Config获取数据库,比较灵活 var db1=db.GetConnection(configId) //非线程安全 (性能好) var db1=db.GetConnectionScope(configId); //线程安全 (解决大部线程安全,性能有些损耗) //方式2:通过特性获取数据库,一个实体对一个库的时候非常方便 var db2=db.GetConnectionWithAttr<T>() //非线程安全 (性能好) var db2=db.GetConnectionScopeWithAttr<T>() //线程安全 (解决大部线程安全,性能有些损耗) [TenantAttribute("1")]//对应ConfigId=1 public class C1Table { public string Id { get; set; } }
接口说明:
ISqlSugarClien childDb=Db.GetConnection("1");//子Db负责CRUD(没有实现ITenant接口) ITenant tenant=Db;//租户负责多库事务和管理子Db //完整Db的接口关系 SqlSugarScope: ISqlSugarClient, ITenant SqlSugarClient: ISqlSugarClient, ITenant
public class Repository<T> : SimpleClient<T> where T : class, new() { public ITenant itenant = null;//多租户事务、GetConnection、IsAnyConnection等功能 public Repository(ISqlSugarClient db) { itenant=db.AsTenant();//用来处理事务 base.Context=db.AsTenant().GetConnectionWithAttr<T>();//获取子Db //GetConnectionScopeWithAttr (解决大部线程安全,性能有损耗) //如果不想通过注入多个仓储 //用到ChangeRepository或者Db.GetMyRepository需要看标题4写法 } }
base.Context=具体数据库对象 可以使用仓储方法在具体数据库进行CRUD
itenant =完整数据库对象 管理多个仓储事务等、还能在使用GetConnection、IsAnyConnection等功能
通过base.仓储方法进行CRUD, itenant负责事务
仓储有哪些方法可以看仓储入门:https://www.donet5.com/Home/Doc?typeId=1228
public class UserRepository { private readonly Repository<Abpusers> rep;//想写几个就写几个 public UserService(Repository<Abpusers> iocrep) { this.rep=iocrep; //IOC仓储配置 //builder.Services.AddScoped(typeof(Repository<>)); } //使用事务 public void TestTran() { try { rep.itenant.BeginTran(); rep.Insert(new UserInfo() {... }); var orderDal= rep.ChangeRepository<Repository<Order>>();//切换仓储 orderDal.Insert(new Order() {... }); orderDal.Context.XXXXX rep.itenant.CommitTran(); } catch (Exception ex) { rep.itenant.RollbackTran(); throw ex; } } }
var orderDal=db.GetRepository<Repository<Order>>();) //使用仓储方法 orderDal.Insert(data);
如果是多仓储注入就可以不用切换仓储,如果你非要用切换仓储写法如下
var orderItemDb = rep.ChangeRepository<Repository<OrderItem>>(); public class Repository<T> : SimpleClient<T> where T : class, new() { Itenant itenant=null;//主db处理事务 public Repository() { //多库下使用该功能需要非构造函数注入 var db=你存储的Services.BuildServiceProvider() .GetService<ISqlSugarClient>(); //教程:https://www.donet5.com/Doc/27/2563 base.Context=db.GetConnectionScopeWithAttr<T>(); //仓储使用当前T的Db this.itenant=db;//主db处理事务 } }
用SqlSugarScope的注意了获取子对象线程安全用法如下
新功能(5.0.7.7preview03+):
this.Context=db.GetConnectionScope(1);//线程安全,子对象也支持了线程安全 this.Context=db.GetConnection(1);//非线安全对象 ,this类需要new ,内部开线程需要new this类
上面主要是原理和实现比较灵活,你也可以用我封好的工作单元 5.0.8.3支持
https://www.donet5.com/Home/Doc?typeId=2360
2016 © donet5.comApache Licence 2.0