diff --git a/visualdev/Tnb.Vengine/AppService/VengineAppService.cs b/visualdev/Tnb.Vengine/AppService/VengineAppService.cs index b65ec3cb..266eccc1 100644 --- a/visualdev/Tnb.Vengine/AppService/VengineAppService.cs +++ b/visualdev/Tnb.Vengine/AppService/VengineAppService.cs @@ -35,6 +35,7 @@ public class VengineAppService : BaseAppService, IVengineAppService _db = _dataAccess.GetSqlSugar(); } + #region 按模型的id进行增删改查接口 /// /// 获取Vmodel /// @@ -47,9 +48,6 @@ public class VengineAppService : BaseAppService, IVengineAppService return _models[id]; } - - #region 按模型的id进行增删改查接口 - /// /// 获取一条 数据信息 /// @@ -68,7 +66,7 @@ public class VengineAppService : BaseAppService, IVengineAppService [HttpGet("api/[area]/[controller]/{vmid}/get-list")] public async Task GetListAsync(string vmid, [FromQuery] VmGetListInput input) { - return await ListAsync(vmid, input.ToQueryInput()); + return await ListAsync(vmid, input.Adapt()); } /// @@ -86,7 +84,7 @@ public class VengineAppService : BaseAppService, IVengineAppService /// 新增 数据 /// [HttpPost("api/[area]/[controller]/{vmid}/create")] - public async Task CreateAsync(string vmid, [FromBody] VmCreateInput input) + public async Task CreateAsync(string vmid, [FromBody] VmEditInput input) { var vm = await GetVmodelAsync(vmid); var ret = await _dataAccess.CreateDataAsync(vm, input); @@ -97,7 +95,7 @@ public class VengineAppService : BaseAppService, IVengineAppService /// 更新 数据 /// [HttpPut("api/[area]/[controller]/{vmid}/update")] - public async Task UpdateAsync(string vmid, [FromBody] VmUpdateInput input) + public async Task UpdateAsync(string vmid, [FromBody] VmEditInput input) { var vm = await GetVmodelAsync(vmid); var ret = await _dataAccess.UpdateDataAsync(vm, input); @@ -147,7 +145,7 @@ public class VengineAppService : BaseAppService, IVengineAppService [HttpGet("api/{areaCode}/{vmCode}/get-list")] public async Task GetListAsync(string areaCode, string vmCode, [FromQuery] VmGetListInput input) { - return await ListAsync(areaCode, vmCode, input.ToQueryInput()); + return await ListAsync(areaCode, vmCode, input.Adapt()); } /// @@ -165,7 +163,7 @@ public class VengineAppService : BaseAppService, IVengineAppService /// 新增 数据 /// [HttpPost("api/{areaCode}/{vmCode}/create")] - public async Task CreateAsync(string areaCode, string vmCode, [FromBody] VmCreateInput input) + public async Task CreateAsync(string areaCode, string vmCode, [FromBody] VmEditInput input) { var vm = await GetVmodelAsync(areaCode, vmCode); var ret = await _dataAccess.CreateDataAsync(vm, input); @@ -176,7 +174,7 @@ public class VengineAppService : BaseAppService, IVengineAppService /// 更新 数据 /// [HttpPut("api/{areaCode}/{vmCode}/update")] - public async Task UpdateAsync(string areaCode, string vmCode, [FromBody] VmUpdateInput input) + public async Task UpdateAsync(string areaCode, string vmCode, [FromBody] VmEditInput input) { var vm = await GetVmodelAsync(areaCode, vmCode); var ret = await _dataAccess.UpdateDataAsync(vm, input); diff --git a/visualdev/Tnb.Vengine/AppService/VengineAppServiceT.cs b/visualdev/Tnb.Vengine/AppService/VengineAppServiceT.cs index 161dc80b..0ea7d967 100644 --- a/visualdev/Tnb.Vengine/AppService/VengineAppServiceT.cs +++ b/visualdev/Tnb.Vengine/AppService/VengineAppServiceT.cs @@ -28,8 +28,8 @@ public class VengineAppService : - VengineAppService + VengineAppService where TEntity : Entity where TGetInput : VmGetInput where TGetListInput : VmGetListInput @@ -169,7 +169,7 @@ public class VengineAppService : - VengineAppService + VengineAppService where TEntity : Entity where TGetInput : VmGetInput where TGetListInput : VmGetListInput @@ -180,7 +180,7 @@ public class VengineAppService : - VengineAppService + VengineAppService where TEntity : Entity where TGetInput : VmGetInput { @@ -189,7 +189,7 @@ public class VengineAppService : } } public class VengineAppService : - VengineAppService + VengineAppService where TEntity : Entity { public VengineAppService(IDataAccess da) : base(da) diff --git a/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs b/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs index 60477402..751388db 100644 --- a/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs +++ b/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs @@ -21,7 +21,7 @@ namespace Tnb.Vengine.AppService; /// [ApiDescriptionSettings(Tag = ModuleConst.Tag, Area = ModuleConst.Area, KeepVerb = true, Order = 1102)] [Route("api/[area]/[controller]/[action]")] -public class VmodelAppService : VengineAppService, IVmodelAppService +public class VmodelAppService : VengineAppService, IVmodelAppService { private readonly IViewEngine _viewEngine; private readonly ICacheManager _cache; @@ -36,51 +36,45 @@ public class VmodelAppService : VengineAppService - /// 获取一条 数据信息 + /// 获取一条 数据信息, q参数无效 /// public override async Task GetAsync(VmodelGetInput input) { - //VmodelGetInput para = new VmodelGetInput(); - //if (!string.IsNullOrEmpty(input.q)) - //{ - // para = input.q.ToObject(); - //} - //var query = _db.Queryable().Where(a => a.deleted == 0); - //Vmodel? vm = null; - //if (!string.IsNullOrEmpty(input.id)) - //{ - // vm = await _dataAccess.GetVmodelAsync(input.id, para.drill); - //} - //else if (!string.IsNullOrEmpty(para.areaCode) && !string.IsNullOrEmpty(para.vmCode)) - //{ - // vm = await _dataAccess.GetVmodelAsync(para.areaCode, para.vmCode, para.drill); - //} - //ThrowIf.IsNull(vm, "输入参数有误, id 和 areaCode,vmCode 不可同时为空"); - return await base.GetAsync(input); + var query = _db.Queryable().Where(a => a.deleted == 0); + Vmodel? vm = null; + if (!string.IsNullOrEmpty(input.id)) + { + vm = await _dataAccess.GetVmodelAsync(input.id, input.drill); + } + else if (!string.IsNullOrEmpty(input.areaCode) && !string.IsNullOrEmpty(input.vmCode)) + { + vm = await _dataAccess.GetVmodelAsync(input.areaCode, input.vmCode, input.drill); + } + ThrowIf.IsNull(vm, "输入参数有误, id 和 areaCode,vmCode 不可同时为空"); + return vm; } - ///// - ///// 获取多条 数据列表 - ///// - //public override async Task> GetListAsync(VmGetListInput input) - //{ - // return await ListAsync(input.ToQueryInput()); - //} + /// + /// 获取多条 数据列表 + /// + public override async Task> GetListAsync(VmGetListInput input) + { + return await ListAsync(input.Adapt()); + } [NonAction] - public override async Task> ListAsync(VmQueryInput input) + public override async Task> ListAsync(VmQueryInput input) { - VmPagedOutput ret = new(); var q = _db.Queryable().WhereIF(!string.IsNullOrEmpty(input.k), a => a.vmCode.Contains(input.k!) || a.vmName.Contains(input.k!)); RefAsync total = 0; var data = await q.OrderBy(input.sort).ToPageListAsync((input.pnum - 1) * input.psize, input.psize, total); - return PagedOutput.Create(total, data.Adapt>()); + return PagedOutput.Create(total, data); } /// /// 新增 模型 /// - public override async Task CreateAsync(VmCreateInput input) + public override async Task CreateAsync(VmodelCreateInput input) { ThrowIf.IsNull(input.data); //ArgumentNullException.ThrowIfNull(input.data); @@ -94,7 +88,7 @@ public class VmodelAppService : VengineAppService /// 更新 数据 /// - public override async Task UpdateAsync(VmUpdateInput input) + public override async Task UpdateAsync(VmodelUpdateInput input) { ThrowIf.IsNull(input.data); //ArgumentNullException.ThrowIfNull(input.data); @@ -104,7 +98,7 @@ public class VmodelAppService : VengineAppService a.naviModel = null); await _db.Updateable(vm).WhereColumns(a => a.id).ExecuteCommandAsync(); await _cache.DelAsync(_dataAccess.GetVmodelCacheKey(vm.id)); - return input; + return vm; } /// diff --git a/visualdev/Tnb.Vengine/AppService/VmodelDto.cs b/visualdev/Tnb.Vengine/AppService/VmodelDto.cs index 352d9d1b..2cbbb864 100644 --- a/visualdev/Tnb.Vengine/AppService/VmodelDto.cs +++ b/visualdev/Tnb.Vengine/AppService/VmodelDto.cs @@ -7,6 +7,29 @@ using Tnb.Vengine.Domain; namespace Tnb.Vengine.AppService; +public class VmodelGetInput : VmGetInput +{ + /// + /// 模块code, areaCode和vmCode为一组 + /// + public string? areaCode { get; set; } + /// + /// 模型code, areaCode和vmCode为一组 + /// + public string? vmCode { get; set; } + /// + /// 是否钻取子模型 + /// + public bool drill { get; set; } = false; +} +public class VmodelCreateInput : VmEditInput +{ + public new Vmodel? data { get; set; } +} +public class VmodelUpdateInput : VmEditInput +{ + public new Vmodel? data { get; set; } +} public class VmodelCreateFromTableInput { public string? dbCode { get; set; } @@ -17,17 +40,19 @@ public class VmodelCreateFromTableInput public string areaCode { get; set; } = "edp"; } -public class CreatePageFromVmodelInput +public class VmodelPageCreateInput : VmEditInput +{ + public new VmodelPage? data { get; set; } +} + +public class VmodelPageUpdateInput : VmEditInput +{ + public new VmodelPage? data { get; set; } +} + +public class VmodelPageCreateFromVmodelInput { public Guid? viewId { get; set; } public string? vmid { get; set; } } -public class VmodelGetInput : VmGetInput -{ - public string? areaCode { get; set; } - public string? vmCode { get; set; } - public string? dbCode { get; set; } - public string? tableName { get; set; } - public bool drill { get; set; } = false; -} \ No newline at end of file diff --git a/visualdev/Tnb.Vengine/AppService/VmodelPageAppService.cs b/visualdev/Tnb.Vengine/AppService/VmodelPageAppService.cs index b086377e..08467778 100644 --- a/visualdev/Tnb.Vengine/AppService/VmodelPageAppService.cs +++ b/visualdev/Tnb.Vengine/AppService/VmodelPageAppService.cs @@ -20,7 +20,7 @@ namespace Tnb.Vengine.AppService; /// [ApiDescriptionSettings(Tag = ModuleConst.Tag, Area = ModuleConst.Area, Order = 1104, KeepVerb = true)] [Route("api/[area]/[controller]/[action]")] -public class VmodelPageAppService : VengineAppService, IVmodelPageAppService +public class VmodelPageAppService : VengineAppService, IVmodelPageAppService { /// /// 构造函数 @@ -29,70 +29,39 @@ public class VmodelPageAppService : VengineAppService, IVmodelPageAp { } - /// - /// 获取一条 数据信息 - /// - public override async Task GetAsync(VmGetInput input) - { - var query = _db.Queryable().Where(a => a.deleted == 0 && a.id == input.id); - VmodelPage vm = await query.FirstAsync(); - return vm; - } + ///// + ///// 新增 模型 + ///// + //public override async Task CreateAsync(VmCreateInput input) + //{ + // ThrowIf.IsNull(input.data); + // VmodelPage vpage = input.data.Adapt(); + // await _db.Insertable(vpage).ExecuteCommandAsync(); + // return vpage; + //} - /// - /// 获取多条 数据列表 - /// - public override async Task> ListAsync(VmQueryInput input) - { - VmPagedOutput ret = new(); - var q = _db.Queryable().WhereIF(!string.IsNullOrEmpty(input.k), a => a.code.Contains(input.k!) || a.name.Contains(input.k!)); - RefAsync total = 0; - var data = await q.OrderBy(input.sort).ToPageListAsync((input.pnum - 1) * input.psize, input.psize, total); - return PagedOutput.Create(total, data.Adapt>()); - } - - /// - /// 新增 模型 - /// - public override async Task CreateAsync(VmCreateInput input) - { - ThrowIf.IsNull(input.data); - VmodelPage vpage = input.data.Adapt(); - await _db.Insertable(vpage).ExecuteCommandAsync(); - return vpage; - } - - /// - /// 更新 数据 - /// - public override async Task UpdateAsync(VmUpdateInput input) - { - ThrowIf.IsNull(input.data); - if (!input.data.ContainsKey(nameof(VmodelPage.id))) - { - throw new Exception($"更新数据时主键({nameof(VmodelPage.id)})不可为空"); - } - var id = input.data[nameof(VmodelPage.id)].ToString(); - var model = await _db.Queryable().FirstAsync(a => a.id == id); - ThrowIf.IsNull(model, $"找不到id={id}的视图页面数据"); - input.data.Adapt(model, TypeAdapter.IgnoreNull); - await _db.Updateable(model).WhereColumns(a => a.id).ExecuteCommandAsync(); - return model; - } - - /// - /// 删除 数据 - /// - public override async Task DeleteAsync(VmDeleteInput input) - { - var ret = await _db.Deleteable(input.id).ExecuteCommandAsync(); - return ret; - } + ///// + ///// 更新 数据 + ///// + //public override async Task UpdateAsync(VmUpdateInput input) + //{ + // ThrowIf.IsNull(input.data); + // if (!input.data.ContainsKey(nameof(VmodelPage.id))) + // { + // throw new Exception($"更新数据时主键({nameof(VmodelPage.id)})不可为空"); + // } + // var id = input.data[nameof(VmodelPage.id)].ToString(); + // var model = await _db.Queryable().FirstAsync(a => a.id == id); + // ThrowIf.IsNull(model, $"找不到id={id}的视图页面数据"); + // input.data.Adapt(model, TypeAdapter.IgnoreNull); + // await _db.Updateable(model).WhereColumns(a => a.id).ExecuteCommandAsync(); + // return model; + //} /// /// 从数据表创建模型 /// - public async Task CreateByVmodel(CreatePageFromVmodelInput input) + public async Task CreateByVmodel(VmodelPageCreateFromVmodelInput input) { ThrowIf.IsNull(input.vmid); var vm = await _dataAccess.GetVmodelAsync(input.vmid); diff --git a/visualdev/Tnb.Vengine/DataAccess/DataAccess.cs b/visualdev/Tnb.Vengine/DataAccess/DataAccess.cs index d5f24ce5..0f2b9a03 100644 --- a/visualdev/Tnb.Vengine/DataAccess/DataAccess.cs +++ b/visualdev/Tnb.Vengine/DataAccess/DataAccess.cs @@ -137,7 +137,7 @@ public class DataAccess : IDataAccess, ITransient, IDisposable { await LoadVmodelNavigateAsync(vm); } - await _cache.SetAsync(id, vm, TimeSpan.FromMinutes(10)); + await _cache.SetAsync(key, vm, TimeSpan.FromMinutes(10)); } return vm; } @@ -211,7 +211,6 @@ public class DataAccess : IDataAccess, ITransient, IDisposable ISqlSugarClient db = GetSqlSugar(vm.dbCode); ISugarQueryable query = db.Queryable().AS(vm.tableName, VmQueryParser.MAIN_ALIES); VmQueryParser parser = new(this, vm, input); - parser.ParseQueryInput(); await parser.LoadNavigateAsync(); // 处理导航属性联表 List joins = parser.GetJoinInfos(); @@ -320,7 +319,7 @@ public class DataAccess : IDataAccess, ITransient, IDisposable /// /// 新增数据 默认方法 /// - public async Task CreateDataAsync(Vmodel vm, VmCreateInput input) + public async Task CreateDataAsync(Vmodel vm, VmEditInput input) { ISqlSugarClient db = GetSqlSugar(vm.dbCode); ThrowIf.When(input.data == null && input.items == null, "新增数据时,data和items不可同时为空"); @@ -386,7 +385,7 @@ public class DataAccess : IDataAccess, ITransient, IDisposable /// /// 更新数据 默认方法 /// - public async Task UpdateDataAsync(Vmodel vm, VmUpdateInput input) + public async Task UpdateDataAsync(Vmodel vm, VmEditInput input) { ISqlSugarClient db = GetSqlSugar(vm.dbCode); VmDbProp pk = vm.GetPrimary(); diff --git a/visualdev/Tnb.Vengine/DataAccess/IDataAccess.cs b/visualdev/Tnb.Vengine/DataAccess/IDataAccess.cs index 09576702..afc4562d 100644 --- a/visualdev/Tnb.Vengine/DataAccess/IDataAccess.cs +++ b/visualdev/Tnb.Vengine/DataAccess/IDataAccess.cs @@ -59,13 +59,13 @@ public interface IDataAccess : ITransient /// /// 新增数据 默认方法 /// - Task CreateDataAsync(Vmodel vm, VmCreateInput input); + Task CreateDataAsync(Vmodel vm, VmEditInput input); //Task UpdateDataAsync(VmUpdateInput input); /// /// 更新数据 默认方法 /// - Task UpdateDataAsync(Vmodel vm, VmUpdateInput input); + Task UpdateDataAsync(Vmodel vm, VmEditInput input); //Task DeleteDataAsync(VmDeleteInput input); /// diff --git a/visualdev/Tnb.Vengine/Domain/VengineDto.cs b/visualdev/Tnb.Vengine/Domain/VengineDto.cs index 1596a454..4e822155 100644 --- a/visualdev/Tnb.Vengine/Domain/VengineDto.cs +++ b/visualdev/Tnb.Vengine/Domain/VengineDto.cs @@ -83,22 +83,6 @@ public class VmGetListInput : VmBaseInput /// 输出字段 /// public string o { get; set; } = "*"; - - /// - /// 转换为QueryInput - /// - /// - public VmQueryInput ToQueryInput() - { - VmQueryInput arg = this.Adapt(); - - if (!string.IsNullOrEmpty(q)) - { - arg.q = q.ToObject(); - } - - return arg; - } } /// @@ -115,7 +99,7 @@ public class VmQueryInput : VmGetListInput /// /// 新增数据输入参数 /// -public class VmCreateInput : VmBaseInput +public class VmEditInput : VmBaseInput { /// /// 数据 @@ -128,17 +112,6 @@ public class VmCreateInput : VmBaseInput public List? items { get; set; } } -/// -/// 修改数据输入参数 -/// -public class VmUpdateInput : VmCreateInput -{ - ///// - ///// 要更新的数据id - ///// - //public string? id { get; set; } -} - /// /// 删除数据输入参数 /// diff --git a/visualdev/Tnb.Vengine/Domain/VmQueryParser.cs b/visualdev/Tnb.Vengine/Domain/VmQueryParser.cs index 8f12616c..3cd197a1 100644 --- a/visualdev/Tnb.Vengine/Domain/VmQueryParser.cs +++ b/visualdev/Tnb.Vengine/Domain/VmQueryParser.cs @@ -24,11 +24,12 @@ internal class VmQueryParser _dataAccess = dataAccess; _root = rootModel; _input = input; + ParseQueryInput(); } /// /// 解析查询参数 /// - public void ParseQueryInput() + private void ParseQueryInput() { // 初始化根模型 Navigates.Clear(); @@ -263,6 +264,92 @@ internal class VmQueryParser /// /// public List GetConditionalModels() + { + List wheres = new(); + // 处理软删除 + var softDeletedProp = _root.GetSoftDeleted(); + if (softDeletedProp != null && !Navigates[MAIN_ALIES].wheres.Any(a => a.code == softDeletedProp.code)) + { + wheres.Add(new ConditionalModel { FieldName = MAIN_ALIES + "." + softDeletedProp.field, FieldValue = "0", ConditionalType = ConditionalType.Equal, CSharpTypeName = softDeletedProp.csType }); + } + + foreach (VmNavigate? nav in Navigates.Values.Where(a => (a.path == MAIN_ALIES || a.navConfig.navType == eNavigateType.OneToOne) && a.wheres.Count > 0)) + { + foreach (VmWhereProp where in nav.wheres) + { + // 当条件为集合数据时 + if (where.value is IEnumerable arrObj) + { + object[] val = arrObj.ToArray(); + string op = val[0].ToString()!; + switch (op) + { + case "><": + wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThan, CSharpTypeName = where.csType }); + wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThan, CSharpTypeName = where.csType }); + break; + case ">=<": + wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThanOrEqual, CSharpTypeName = where.csType }); + wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThan, CSharpTypeName = where.csType }); + break; + case "><=": + wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThan, CSharpTypeName = where.csType }); + wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThanOrEqual, CSharpTypeName = where.csType }); + break; + case ">=<=": + wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThanOrEqual, CSharpTypeName = where.csType }); + wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThanOrEqual, CSharpTypeName = where.csType }); + break; + case "in": + wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = string.Join(',', val.Skip(1)), ConditionalType = ConditionalType.In, CSharpTypeName = where.csType }); + break; + default: op = string.Empty; break; + } + } + else + { + ConditionalType conditionalType = ConditionalType.Equal; + string? value = where.value?.ToString(); + if (string.IsNullOrEmpty(value)) + { + continue; + } + + if (value.Length >= 2) + { + string op = value[..2]; + switch (op) + { + case "%%": conditionalType = ConditionalType.Like; break; + case ">>": conditionalType = ConditionalType.GreaterThan; break; + case "<<": conditionalType = ConditionalType.LessThan; break; + case ">=": conditionalType = ConditionalType.GreaterThanOrEqual; break; + case "<=": conditionalType = ConditionalType.LessThanOrEqual; break; + case "==": conditionalType = ConditionalType.Equal; break; + default: op = string.Empty; break; + } + if (!string.IsNullOrEmpty(op)) + { + value = value.RemovePreFix(op); + if (value.ToLower() == "null") + { + value = null; + } + } + } + wheres.Add(new ConditionalModel { FieldName = where.fieldName, FieldValue = value, ConditionalType = conditionalType, CSharpTypeName = where.csType }); + } + } + } + return wheres; + } + + /// + /// 生成查询过滤条件 + /// + /// + /// + public List FilterSofeDeleted() { List wheres = new(); foreach (VmNavigate? nav in Navigates.Values.Where(a => (a.path == MAIN_ALIES || a.navConfig.navType == eNavigateType.OneToOne) && a.wheres.Count > 0)) diff --git a/visualdev/Tnb.Vengine/Domain/Vmodel.cs b/visualdev/Tnb.Vengine/Domain/Vmodel.cs index 737e8564..27e72305 100644 --- a/visualdev/Tnb.Vengine/Domain/Vmodel.cs +++ b/visualdev/Tnb.Vengine/Domain/Vmodel.cs @@ -23,6 +23,8 @@ namespace Tnb.Vengine.Domain; [SugarTable("sys_vmodel")] public partial class Vmodel : Entity { + public string[] SOFT_DELETED = new string[] { "deleted", "isDeleted", "softDeleted" }; + #region Properties /// @@ -188,12 +190,23 @@ public partial class Vmodel : Entity } /// - /// 获取模型的主键字段属性 + /// 获取模型的主键属性 /// /// public VmDbProp GetPrimary() { - return dbProps.First(a => a.pkey); + var key = dbProps.FirstOrDefault(a => a.pkey); + ThrowIf.IsNull(key, $"模型({fullCode})没有定义主键属性"); + return key; + } + + /// + /// 获取模型的软删除属性 + /// + /// + public VmDbProp? GetSoftDeleted() + { + return dbProps.FirstOrDefault(a => SOFT_DELETED.Contains(a.code)); } ///