///////////////////////////////////////////////////////////////////////////////// // 宁波拓通e智造平台 ToTong Next Builder // // https://git.tuotong-tech.com/tnb/tnb.server // ///////////////////////////////////////////////////////////////////////////////// using System.Collections.Concurrent; using JNPF; using JNPF.DependencyInjection; using Mapster; using SqlSugar; using Tnb.Vengine.Domain; namespace Tnb.Vengine.DataAccess; /// /// /// public class DataAccess : IDataAccess, ITransient, IDisposable { const int MAX_PAGE_SIZE = 1000; private ISqlSugarClient? sugar; protected ISqlSugarClient Db { get { if (sugar == null) { ConnectionStringsOptions conn = App.GetConfig("ConnectionStrings", true); //var DBType = (DbType)Enum.Parse(typeof(DbType), conn.DBType); sugar = new SqlSugarScope(new ConnectionConfig { ConnectionString = conn.ConnectString, DbType = conn.DBType.Adapt(), IsAutoCloseConnection = true, ConfigId = conn.ConfigId, InitKeyType = InitKeyType.Attribute, MoreSettings = new ConnMoreSettings() { IsAutoRemoveDataCache = true, // 自动清理缓存 IsAutoToUpper = false, PgSqlIsAutoToLower = false, DisableNvarchar = true }, }, SugarHelper.ConfigSugar); } return sugar; } } /// /// 全局缓存 /// static ConcurrentDictionary DbCache = new ConcurrentDictionary(); /// /// 构造 /// public DataAccess() { } /// /// 释放 /// public void Dispose() { foreach (var item in DbCache) { item.Value.Dispose(); } DbCache.Clear(); } /// /// 获取 ISqlSugarClient /// public ISqlSugarClient GetSqlSugar(string? dbCode = null) { if (string.IsNullOrEmpty(dbCode) || dbCode == DbConsts.DefaultDbCode) { return Db; } if (DbCache.ContainsKey(dbCode)) { return DbCache[dbCode]; } var dblink = GetVmLink(dbCode); if (dblink == null) { throw new Exception($"没有此数据库{dbCode}连接信息"); } var dbType = Enum.Parse(dblink.dbType.ToString(), true); var sugar = new SqlSugarScope(new ConnectionConfig { ConnectionString = dblink.dbConnection, DbType = dbType, IsAutoCloseConnection = true, ConfigId = dblink.dbCode, InitKeyType = InitKeyType.Attribute, MoreSettings = new ConnMoreSettings() { IsAutoRemoveDataCache = true, // 自动清理缓存 IsAutoToUpper = false, PgSqlIsAutoToLower = false, DisableNvarchar = true }, }, SugarHelper.ConfigSugar); if (sugar.Ado.IsValidConnection()) { DbCache[dbCode] = sugar; } else { sugar.Dispose(); throw new Exception($"无法连接到数据库{dbCode}"); } return DbCache[dbCode]; } /// /// 获取 DbLink /// public VmodelLink GetVmLink(string dbCode) { var model = Db.Queryable().First(a => a.dbCode == dbCode); return model; } /// /// 获取 Vmodel, 为空时不抛异常 /// public async Task TryGetVmodelAsync(string id, bool loadNavigate = false) { Vmodel vm = await Db.Queryable().FirstAsync(a => a.id == id && a.deleted == 0); if (vm != null && loadNavigate) { await LoadVmodelNavigateAsync(vm); } return vm; } /// /// 获取 Vmodel, 为空时抛异常 /// public async Task GetVmodelAsync(string id, bool loadNavigate = false) { Vmodel vm = await Db.Queryable().FirstAsync(a => a.id == id && a.deleted == 0); ArgumentNullException.ThrowIfNull(vm, $"找不到vmid={id}的模型"); if (loadNavigate) { await LoadVmodelNavigateAsync(vm); } return vm; } /// /// 获取 Vmodel, 为空时不抛异常 /// public async Task TryGetVmodelAsync(string area, string vmCode, bool loadNavigate = false) { Vmodel vm = await Db.Queryable().FirstAsync(a => a.area == area && a.vmCode == vmCode && a.deleted == 0); if (vm != null && loadNavigate) { await LoadVmodelNavigateAsync(vm); } return vm; } /// /// 获取 Vmodel, 为空时抛异常 /// public async Task GetVmodelAsync(string area, string vmCode, bool loadNavigate = false) { Vmodel vm = await Db.Queryable().FirstAsync(a => a.area == area && a.vmCode == vmCode && a.deleted == 0); ArgumentNullException.ThrowIfNull(vm, $"找不到area={area}, vmCode={vmCode}的模型"); if (loadNavigate) { await LoadVmodelNavigateAsync(vm); } return vm; } ///// ///// 获取 Vmodel ///// //public async Task GetVmodelAsync(string tableName, string? dbCode) //{ // Vmodel vm = await _db.Queryable().FirstAsync(a => a.tableName == tableName && a.dbCode == dbCode && a.deleted == 0); // return vm; //} /// /// 加载模型的导航属性 /// /// /// private async Task LoadVmodelNavigateAsync(Vmodel vm) { Dictionary dictVm = new(); foreach (var navProp in vm.navProps) { if (!dictVm.ContainsKey(navProp.vmid)) { var navModel = await GetVmodelAsync(navProp.vmid); dictVm.Add(navProp.vmid, navModel); } navProp.naviModel = dictVm[navProp.vmid]; } } /// /// 查询数据 默认方法 /// public async Task QueryDataAsync(Vmodel vm, VmQueryInput input) { ISqlSugarClient db = GetSqlSugar(vm.dbCode); var query = db.Queryable().AS(vm.tableName, VmSelectProp.MAIN_ALIES); var selProps = vm.GetVmSelectProps(input.o); //处理导航属性联表 List joins = vm.GetJoinInfos(selProps); query.AddJoinInfo(joins); List wheres = vm.GetConditionalModels(input.q); if (!string.IsNullOrEmpty(input.k)) { var lsCondition = new List>(); var wType = WhereType.And; foreach (var prop in vm.dbProps.Where(a => a.fuzzy)) { lsCondition.Add(new(wType, new ConditionalModel() { FieldName = prop.field, ConditionalType = ConditionalType.Like, FieldValue = input.k })); wType = WhereType.Or; } wheres.Add(new ConditionalCollections() { ConditionalList = lsCondition }); } //处理查询参数 query.Where(wheres); if (!string.IsNullOrEmpty(input.sort)) { query.OrderBy(input.sort); } //处理输出字段 List selects = vm.GetSelectModels(selProps); query.Select(selects); //查询数据 VmPagedOutput result = new(); List> ls = new(); int skip = input.pnum > 0 ? (input.pnum - 1) * input.psize : 0; int take = input.psize == 0 ? MAX_PAGE_SIZE : input.psize; if (input.pnum > 0) { result.total = await query.CountAsync(); } ls = await query.Skip(skip).Take(take).ToDictionaryListAsync(); //组装输出对象 foreach (var data in ls) { DObject ret = await NestedOutputAsync(vm, data, selProps); result.items.Add(ret); } return result; } /// /// 组装子模型对象 /// /// /// /// /// private async Task NestedOutputAsync(Vmodel vm, Dictionary src, List selProps) { DObject ret = new(); foreach (var prop in selProps) { if (prop.navType == eNavigateType.None || prop.navCode == VmSelectProp.MAIN_ALIES) { if (src.ContainsKey(prop.code)) { ret.Add(prop.code, src[prop.code]); } } else { if (prop.navType == eNavigateType.OneToOne) { var key = prop.navCode + "_" + prop.code; ret.Add(key, src[key]); //if (!ret.ContainsKey(prop.navCode)) //{ // ret.Add(prop.navCode, new DObject()); //} //var key = prop.navCode + "_" + prop.code; //if (src.ContainsKey(key)) //{ // ((DObject)ret[prop.navCode]).Add(prop.code, src[key]); //} } else if (prop.navType == eNavigateType.OneToMany) { if (!ret.ContainsKey(prop.navCode)) { ret.Add(prop.navCode, new List()); } var navProp = vm.navProps.First(a => a.code == prop.navCode); if (navProp != null && navProp.naviModel != null && src.ContainsKey(navProp.refField)) { VmQueryInput input = new VmQueryInput(); input.q = new DObject(navProp.refField, src[navProp.refField]); input.o = string.Join(',', selProps.Where(a => a.navCode == prop.navCode).Select(a => a.code)); ret[prop.navCode] = (await QueryDataAsync(navProp.naviModel, input)).items; } } else if (prop.navType == eNavigateType.ManyToMany) { if (!ret.ContainsKey(prop.navCode)) { ret.Add(prop.navCode, new List()); } } } } return ret; } /// /// 新增数据 默认方法 /// public async Task CreateDataAsync(Vmodel vm, VmCreateInput input) { ISqlSugarClient db = GetSqlSugar(vm.dbCode); int num = 0; if (input.data != null) { var model = vm.PropToField(input.data); num = await db.Insertable(model).AS(vm.tableName).ExecuteCommandAsync(); return input.data; } else if (input.items != null) { List lst = new List(); foreach (var item in input.items) { lst.Add(vm.PropToField(item)); } num = await db.Insertable(lst).AS(vm.tableName).ExecuteCommandAsync(); return input.items; } else { input.data = vm.GetDefaultDObject(); var model = vm.PropToField(input.data); num = await db.Insertable(model).AS(vm.tableName).ExecuteCommandAsync(); return input.data; } } /// /// 更新数据 默认方法 /// public async Task UpdateDataAsync(Vmodel vm, VmUpdateInput input) { ISqlSugarClient db = GetSqlSugar(vm.dbCode); var pk = vm.GetPrimary(); int num = 0; if (input.data != null) { var model = vm.PropToField(input.data); if (!model.ContainsKey(pk.field)) { throw new Exception($"更新数据时主键({pk.code})不可为空"); } //if (!model.ContainsKey(pk.field) && input.id != null) //{ // model.Add(pk.field, input.id); //} num = await db.Updateable(model).AS(vm.tableName).WhereColumns(pk.field).ExecuteCommandAsync(); } else if (input.items != null) { List lst = new(); foreach (var item in input.items) { var model = vm.PropToField(item); if (model.ContainsKey(pk.field)) { lst.Add(model); } } num = await db.Updateable(lst).AS(vm.tableName).WhereColumns(pk.field).ExecuteCommandAsync(); } return num; } /// /// 删除数据 默认方法 /// public async Task DeleteDataAsync(Vmodel vm, VmDeleteInput input) { ISqlSugarClient db = GetSqlSugar(vm.dbCode); var pk = vm.GetPrimary(); int num = 0; List> ids = new(); if (input.id != null) { ids.Add(new DObject(pk.field, input.id)); } else if (input.ids != null) { ids.AddRange(input.ids.Select(a => new DObject(pk.field, a))); } if (ids.Count > 0) { num = await db.Deleteable().AS(vm.tableName).WhereColumns(ids).ExecuteCommandAsync(); } return num; } }