完善模型通用接口的无限层级一对一和单层级一对多

This commit is contained in:
2023-11-15 13:43:24 +08:00
parent d800987307
commit 9c03ef2bcc
145 changed files with 758 additions and 10219 deletions

View File

@@ -67,9 +67,9 @@ public class VmGetListInput : VmBaseInput
/// </summary>
public string o { get; set; } = "*";
public VmListInput ToListInput()
public VmQueryInput ToListInput()
{
VmListInput arg = this.Adapt<VmListInput>();
VmQueryInput arg = this.Adapt<VmQueryInput>();
if (!string.IsNullOrEmpty(q))
{
@@ -83,7 +83,7 @@ public class VmGetListInput : VmBaseInput
/// <summary>
/// 获取多条数据输入参数
/// </summary>
public class VmListInput : VmGetListInput
public class VmQueryInput : VmGetListInput
{
/// <summary>
/// 查询条件
@@ -152,20 +152,20 @@ public class PagedOutput<T>
/// <summary>
/// 动态分页列表输出对象
/// </summary>
public class VmPagedOutput : PagedOutput<dynamic>
public class VmPagedOutput : PagedOutput<DObject>
{
}
/// <summary>
/// 查询属性信息
/// </summary>
public class VmSelectProp
{
public const string MAIN_ALIES = "m";
public string code { get; set; } = string.Empty;
public string field { get; set; } = string.Empty;
public List<string> navPath { get; set; } = new List<string>();
public string navCode { get; set; } = MAIN_ALIES;
public ePropType propType { get; set; }
public eNavigateType navType { get; set; }
}
///// <summary>
///// 查询属性信息
///// </summary>
//public class VmSelectProp
//{
// public const string MAIN_ALIES = "m";
// public string code { get; set; } = string.Empty;
// public string field { get; set; } = string.Empty;
// public List<string> navPath { get; set; } = new List<string>();
// public string navCode { get; set; } = MAIN_ALIES;
// public ePropType propType { get; set; }
// public eNavigateType navType { get; set; }
//}

View File

@@ -30,7 +30,7 @@ public class VmDbProp : VmBaseProp
/// <summary>
/// 数据类型
/// </summary>
public string? csType { get; set; }
public string csType { get; set; } = "string";
/// <summary>
/// 长度

View File

@@ -27,17 +27,17 @@ public class VmNavProp : VmBaseProp
/// <summary>
/// 源表代码,默认为m,表示与主表关联,可设置为中间表导航属性code,用来表示多对多
/// </summary>
public string refCode { get; set; } = VmSelectProp.MAIN_ALIES;
public string refCode { get; set; } = VmQueryParser.MAIN_ALIES;
/// <summary>
/// 源表字段, 源表的外键字段
/// </summary>
public string refField { get; set; } = string.Empty;
public string refProp { get; set; } = string.Empty;
/// <summary>
/// 导航表字段
/// </summary>
public string fkField { get; set; } = string.Empty;
public string fkProp { get; set; } = string.Empty;
/// <summary>
/// 关联模型

View File

@@ -1,105 +1,508 @@
using JNPF.Common.Extension;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Drawing.Drawing2D;
using NPOI.OpenXmlFormats.Dml.Diagram;
using SqlSugar;
using Tnb.Core;
using Tnb.Vengine.DataAccess;
namespace Tnb.Vengine.Domain
namespace Tnb.Vengine.Domain;
internal class VmQueryParser
{
public class VmQueryParser
public const string MAIN_ALIES = "m";
public const char NAVI_SEPERATE = '.';
public const char PROP_SEPERATE = '&';
private readonly IDataAccess _dataAccess;
private readonly Vmodel _root;
private readonly VmQueryInput _input;
public Dictionary<string, VmNavigate> Navigates { get; } = new Dictionary<string, VmNavigate>();
public VmQueryParser(IDataAccess dataAccess, Vmodel rootModel, VmQueryInput input)
{
private readonly IDataAccess _dataAccess;
private readonly Vmodel _root;
private List<string> _outputs;
private Dictionary<string, VmSelect> _selectProps = new Dictionary<string, VmSelect>();
private Dictionary<string, Vmodel?> _navModels = new Dictionary<string, Vmodel?>();
public VmQueryParser(IDataAccess dataAccess, Vmodel rootModel, string output)
{
_dataAccess = dataAccess;
_root = rootModel;
ParseOutputStr(output);
}
/// <summary>
/// 按模型组织要输出的属性
/// </summary>
private void ParseOutputStr(string output)
{
_outputs = output.Split(',').Distinct().ToList();
_selectProps.Add(Vmodel.MAIN_ALIES, new VmSelect() { navModel = _root });
foreach (var outStr in _outputs)
{
if (string.IsNullOrWhiteSpace(outStr)) continue;
var codes = outStr.Split('.');
if (codes.Length == 1)
{
_selectProps[Vmodel.MAIN_ALIES].propCodes.Add(outStr);
continue;
}
var vmPath = "";
for (int i = 0; i < codes.Length - 1; i++)
{
vmPath = i == 0 ? codes[i] : vmPath + "." + codes[i];
if (!_selectProps.ContainsKey(vmPath))
{
_selectProps.Add(vmPath, new VmSelect(vmPath, i + 2));
}
if (i == codes.Length - 2)
{
_selectProps[vmPath].propCodes.Add(codes[i + 1]);
}
}
}
}
private async Task LoadNavModel()
{
var keys = _selectProps.Keys.Where(a => a != Vmodel.MAIN_ALIES).OrderBy(a => a).ToList();
foreach (var selVm in _selectProps.Values)
{
if (_navModels.ContainsKey(selVm.path))
{
continue;
}
}
var navProps = _root.navProps.Where(a => _selectProps.Values.Any(b => b.path.StartsWith(a.code + "."))).ToList();
await LoadVmodelNavigateAsync(navProps);
}
private async Task LoadVmodelNavigateAsync(List<VmNavProp> navProps)
{
var db = _dataAccess.GetSqlSugar();
var vmids = navProps.Select(a => a.vmid).Distinct().ToList();
var navs = await db.Queryable<Vmodel>().Where(a => vmids.Contains(a.id)).ToDictionaryAsync(a => a.id, a => a);
foreach (var navProp in navProps)
{
navProp.naviModel = (Vmodel)navs.GetOrDefault(navProp.vmid);
navProp.naviModel.navProps.Where(a => _selectProps.Values.Any(b => b.path.StartsWith(a.code + "."))).ToList();
}
}
_dataAccess = dataAccess;
_root = rootModel;
_input = input;
}
/// <summary>
/// 解析查询参数
/// </summary>
public void ParseQueryInput()
{
// 初始化根模型
Navigates.Clear();
VmNavigate main = new(MAIN_ALIES);
main.navConfig.naviModel = _root;
Navigates.Add(MAIN_ALIES, main);
ParseOutputStr(_input.o);
ParseQueryPara(_input.q);
ParseSortPara(_input.sort);
}
internal class VmSelect
/// <summary>
/// 清除字符串特殊符号
/// </summary>
private string ClearStr(string str)
{
public Vmodel? navModel { get; set; }
public string path { get; set; } = Vmodel.MAIN_ALIES;
public int level { get; set; } = 1;
public eNavigateType navType { get; set; } = eNavigateType.None;
public List<string> navPaths { get; set; } = new List<string>();
return str.Trim(' ', '\r', '\n', '\t');
}
public List<string> propCodes { get; set; } = new List<string>();
public List<string> fieldCodes { get; set; } = new List<string>();
/// <summary>
/// 解析输出属性字符串
/// </summary>
private void ParseOutputStr(string output)
{
// t1.t2.id
List<string> outputs = output.Split(',').Distinct().ToList();
foreach (string? outStr in outputs)
{
_ = ClearStr(outStr);
if (string.IsNullOrWhiteSpace(outStr))
{
continue;
}
// t1 t2 id
string[] codes = outStr.Split(NAVI_SEPERATE);
public VmSelect()
{
}
public VmSelect(string vmPath, int vmLevel)
{
path = vmPath;
level = vmLevel;
// 根据导航路径添加选择器
string vmPath = MAIN_ALIES;
for (int i = 0; i < codes.Length - 1; i++)
{
string code = ClearStr(codes[i]);
vmPath = i == 0 ? code : vmPath + NAVI_SEPERATE + code;
if (!Navigates.ContainsKey(vmPath))
{
Navigates.Add(vmPath, new VmNavigate(vmPath));
}
}
// 添加返回的属性到选择器
string lastCode = ClearStr(codes[^1]);
Navigates[vmPath].selects.Add(new VmSelectProp(lastCode));
}
}
internal class NavigateVmodel
/// <summary>
/// 解析查询参数
/// </summary>
private void ParseQueryPara(DObject? query)
{
public Vmodel? navModel { get; set; }
public string navPath { get; set; }
if (query == null)
{
return;
}
foreach (KeyValuePair<string, object> item in query)
{
string[] codes = item.Key.Split(NAVI_SEPERATE);
// 将导航属性查询条件添加到选择器
string vmPath = MAIN_ALIES;
for (int i = 0; i < codes.Length - 1; i++)
{
string code = ClearStr(codes[i]);
vmPath = i == 0 ? code : vmPath + NAVI_SEPERATE + code;
if (!Navigates.ContainsKey(vmPath))
{
Navigates.Add(vmPath, new VmNavigate(vmPath));
}
}
// 添加返回的属性到选择器
string lastCode = ClearStr(codes[^1]);
Navigates[vmPath].wheres.Add(new VmWhereProp(lastCode) { value = item.Value });
}
}
/// <summary>
/// 解析排序参数
/// </summary>
private void ParseSortPara(string? sort)
{
if (string.IsNullOrWhiteSpace(sort))
{
return;
}
string[] orders = sort.Split(',');
foreach (string orderStr in orders)
{
_ = ClearStr(orderStr);
if (string.IsNullOrWhiteSpace(orderStr))
{
continue;
}
// 拆分 m.code desc
string[] codes = orderStr.Split(' ', 1);
// 拆分 m.code
(string?, string) orderPath = codes[0].GetParent(NAVI_SEPERATE);
orderPath.Item1 ??= MAIN_ALIES;
ThrowIf.When(!Navigates.ContainsKey(orderPath.Item1), $"排序参数{orderStr}错误,导航路径{orderPath.Item1}必须包含在输出参数中");
VmOrderProp orderby = new(orderPath.Item2);
if (codes.Length == 2)
{
OrderByType? orderType = codes[1].ToLower() switch
{
"asc" => OrderByType.Asc,
"desc" => OrderByType.Desc,
_ => null
};
ThrowIf.IsNull(orderType, $"排序方式{orderStr}不正确");
orderby.orderType = orderType.Value;
}
Navigates[orderPath.Item1].orders.Add(orderby);
}
}
/// <summary>
/// 加载单个导航属性模型
/// </summary>
private async Task<Vmodel> LoadVmNavigateModelAsync(VmNavigate nav, Dictionary<string, VmNavigate> navs)
{
if (nav.navConfig.naviModel != null)
{
return nav.navConfig.naviModel;
}
// 分割导航路径, a.b.c -> a.b, c
(string?, string) path = nav.path.GetParent(NAVI_SEPERATE);
path.Item1 ??= MAIN_ALIES;
nav.parent = Navigates[path.Item1];
Vmodel parentVm = await LoadVmNavigateModelAsync(nav.parent, navs);
// 获取导航属性配置
nav.navConfig = parentVm.navProps.FirstOrDefault(a => a.code == path.Item2)!;
ThrowIf.IsNull(nav.navConfig, $"模型({parentVm.fullCode})的导航属性{nav.path}配置错误: 找不到(code = {path.Item2})的导航属性");
// 获取导航模型
nav.navConfig.naviModel = await _dataAccess.GetVmodelAsync(nav.navConfig.vmid);
ThrowIf.IsNull(nav.navConfig.naviModel, $"模型({parentVm.fullCode})的导航属性{nav.path}配置错误: 找不到(id = {nav.navConfig.vmid})的模型");
// 处理导航模型
if (nav.navConfig.refCode == MAIN_ALIES)
{
var field = nav.parent.navConfig.naviModel!.PropToFieldCode(nav.navConfig.refProp);
ThrowIf.IsNull(field, $"模型({parentVm.fullCode})的导航属性{nav.path}配置错误: 找不到(code = {nav.navConfig.refProp})的字段");
field = nav.navConfig.naviModel.PropToFieldCode(nav.navConfig.fkProp);
ThrowIf.IsNull(field, $"模型({parentVm.fullCode})的导航属性{nav.path}配置错误: 在子模型{nav.navConfig.naviModel.fullCode}中找不到(code = {nav.navConfig.fkProp})的字段");
if (!nav.parent.selects.Any(a => a.code == nav.navConfig.refProp))
{
nav.parent.selects.Add(new VmSelectProp(nav.navConfig.refProp));
}
if (!nav.selects.Any(a => a.code == nav.navConfig.fkProp))
{
nav.selects.Add(new VmSelectProp(nav.navConfig.fkProp));
}
}
else
{
var navPath = nav.path + NAVI_SEPERATE + nav.navConfig.refCode;
if (!Navigates.ContainsKey(navPath))
{
VmNavigate midNav = new VmNavigate(navPath);
midNav.navConfig = parentVm.navProps.FirstOrDefault(a => a.code == nav.navConfig.refCode)!;
ThrowIf.IsNull(midNav.navConfig, $"模型({parentVm.fullCode})的导航属性{midNav.path}配置错误: 找不到(code = {nav.navConfig.refCode})的导航属性");
midNav.navConfig.naviModel = await _dataAccess.GetVmodelAsync(midNav.navConfig.vmid);
ThrowIf.IsNull(midNav.navConfig.naviModel, $"模型({parentVm.fullCode})的导航属性{midNav.path}配置错误: 找不到(id = {midNav.navConfig.vmid})的模型");
}
}
return nav.navConfig.naviModel;
}
/// <summary>
/// 加载单个导航属性模型
/// </summary>
public async Task LoadNavigateAsync()
{
Dictionary<string, VmNavigate> tobeAdd = new Dictionary<string, VmNavigate>();
foreach (VmNavigate nav in Navigates.Values)
{
_ = await LoadVmNavigateModelAsync(nav, tobeAdd);
}
foreach (var item in tobeAdd)
{
Navigates.Add(item.Key, item.Value);
}
foreach (VmNavigate nav in Navigates.Values)
{
nav.HandleStar();
nav.LoadDbProp();
}
}
/// <summary>
/// 处理一对一联表关系,生成联表信息
/// </summary>
/// <param name="selProps"></param>
/// <remarks>SELECT * FROM wms_distask_h m INNER JOIN eqp_equipment equip ON m.device_id=equip."id" INNER JOIN eqp_equip_type equipType ON equip.equip_type_id=equipType."id"</remarks>
/// <returns></returns>
public List<JoinInfoParameter> GetJoinInfos()
{
List<JoinInfoParameter> joins = new();
// 主查询中只处理主表和一对一的联表
IEnumerable<VmNavigate> navs = Navigates.Values.Where(a => a.path != MAIN_ALIES && a.navConfig.navType == eNavigateType.OneToOne);
foreach (VmNavigate? nav in navs)
{
Debug.Assert(nav.parent != null && nav.navConfig.naviModel != null);
JoinInfoParameter join = new() { TableName = nav.navConfig.naviModel.tableName, ShortName = nav.pathCode, Type = JoinType.Left };
var refNav = nav.navConfig.refCode == MAIN_ALIES ? nav.parent : Navigates[nav.path + "." + nav.navConfig.refCode];
var fkField = nav.navConfig.naviModel.PropToFieldCode(nav.navConfig.fkProp);
var refField = refNav.navConfig.naviModel!.PropToFieldCode(nav.navConfig.refProp);
join.Models = ObjectFuncModel.Create("Equals", $"{nav.pathCode}.{fkField}", $"{refNav.pathCode}.{refField}");
joins.Add(join);
}
return joins;
}
/// <summary>
/// 生成查询过滤条件
/// </summary>
/// <param name="filter"></param>
/// <returns></returns>
public List<IConditionalModel> GetConditionalModels()
{
List<IConditionalModel> wheres = new();
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<object> 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;
}
/// <summary>
/// 生成按关键字查询的条件列表
/// </summary>
/// <param name="drill">是否钻取子表关键词查询</param>
/// <returns></returns>
public ConditionalCollections GetKeywordConditional(bool drill = true)
{
ConditionalCollections conditionals = new() { ConditionalList = new List<KeyValuePair<WhereType, ConditionalModel>>() };
if (string.IsNullOrWhiteSpace(_input.k))
{
return conditionals;
}
WhereType wType = WhereType.And;
IEnumerable<VmNavigate> navs = Navigates.Values.WhereIF(!drill, a => a.path == MAIN_ALIES).Where(a => a.navConfig.navType != eNavigateType.OneToMany);
foreach (VmNavigate? nav in navs)
{
foreach (VmSelectProp? prop in nav.selects.Where(a => a.fuzzy))
{
conditionals.ConditionalList.Add(new(wType, new ConditionalModel() { FieldName = prop.fieldName, ConditionalType = ConditionalType.Like, FieldValue = _input.k, CSharpTypeName = prop.csType }));
wType = WhereType.Or;
}
}
return conditionals;
}
/// <summary>
/// 生成排序条件列表
/// </summary>
/// <returns></returns>
public List<OrderByModel> GetOrderByModels()
{
IEnumerable<VmNavigate> navs = Navigates.Values.Where(a => a.orders.Count > 0);
return navs.SelectMany(a =>
{
return a.orders.Select(b => new OrderByModel
{
FieldName = b.fieldName,
OrderByType = b.orderType
});
}).ToList();
}
/// <summary>
/// 生成查询字段列表
/// </summary>
/// <param name="selProps"></param>
/// <returns></returns>
public List<SelectModel> GetSelectModels()
{
IEnumerable<VmNavigate> navs = Navigates.Values.Where(a => (a.path == MAIN_ALIES || a.navConfig.navType == eNavigateType.OneToOne) && a.selects.Count > 0);
return navs.SelectMany(a =>
{
return a.selects.Select(b => new SelectModel
{
FiledName = b.fieldName,
AsName = (a.path == MAIN_ALIES ? "" : a.pathCode + PROP_SEPERATE) + b.code
});
}).ToList();
}
}
internal class VmNavigate
{
public VmNavigate? parent { get; set; }
public VmNavProp navConfig { get; set; } = new VmNavProp();
public string path { get; set; }
public string pathCode { get; set; }
public List<VmSelectProp> selects { get; set; } = new List<VmSelectProp>();
public List<VmWhereProp> wheres { get; set; } = new List<VmWhereProp>();
public List<VmOrderProp> orders { get; set; } = new List<VmOrderProp>();
public VmNavigate(string vmPath)
{
path = vmPath;
pathCode = vmPath.Replace(VmQueryParser.NAVI_SEPERATE, VmQueryParser.PROP_SEPERATE);
}
/// <summary>
/// 处理占位符星号
/// </summary>
public void HandleStar()
{
if (selects.Any(a => a.code == "*"))
{
selects.Clear();
navConfig.naviModel!.dbProps.ForEach(a =>
{
selects.Add(new VmSelectProp(a.code));
});
}
}
/// <summary>
/// 将属性名转换为字段名
/// </summary>
public void LoadDbProp()
{
foreach (VmSelectProp item in selects)
{
VmDbProp? prop = navConfig.naviModel!.GetDbProp(item.code);
ThrowIf.IsNull(prop, $"输出参数{path}.{item.code}错误: 在模型{navConfig.naviModel.fullCode}中找不到属性({item.code})对应的字段");
item.field = prop.field;
item.fieldName = pathCode + "." + item.field;
item.fuzzy = prop.fuzzy;
item.csType = prop.csType;
item.asName = (path == VmQueryParser.MAIN_ALIES ? "" : pathCode + VmQueryParser.PROP_SEPERATE) + item.code;
}
foreach (VmOrderProp item in orders)
{
VmDbProp? prop = navConfig.naviModel!.GetDbProp(item.code);
ThrowIf.IsNull(prop, $"排序参数{path}.{item.code}错误: 在模型{navConfig.naviModel.fullCode}中找不到属性({item.code})对应的字段");
item.field = prop.field;
item.fieldName = pathCode + "." + item.field;
}
foreach (VmWhereProp item in wheres)
{
VmDbProp? prop = navConfig.naviModel!.GetDbProp(item.code);
ThrowIf.IsNull(prop, $"查询参数{path}.{item.code}错误: 在模型{navConfig.naviModel.fullCode}中找不到属性({item.code})对应的字段");
item.field = prop.field;
item.fieldName = pathCode + "." + item.field;
item.csType = prop.csType;
}
//props.RemoveAll(a => string.IsNullOrEmpty(a.field));
}
}
internal class VmQueryBaseProp
{
public string code { get; set; }
public string field { get; set; } = string.Empty;
public string fieldName { get; set; } = string.Empty;
public VmQueryBaseProp(string code)
{
this.code = code;
}
}
internal class VmSelectProp : VmQueryBaseProp
{
public string asName { get; set; } = string.Empty;
public string csType { get; set; } = "string";
public bool fuzzy { get; set; }
public VmSelectProp(string code) : base(code)
{
}
}
internal class VmOrderProp : VmQueryBaseProp
{
public OrderByType orderType { get; set; } = OrderByType.Asc;
public VmOrderProp(string code) : base(code)
{
}
}
internal class VmWhereProp : VmQueryBaseProp
{
public string csType { get; set; } = "string";
[AllowNull]
public object value { get; set; }
public VmWhereProp(string code) : base(code)
{
}
}

View File

@@ -23,8 +23,6 @@ namespace Tnb.Vengine.Domain;
[SugarTable("sys_vmodel")]
public partial class Vmodel : Entity
{
public const string MAIN_ALIES = "m";
#region Properties
/// <summary>
@@ -139,9 +137,6 @@ public partial class Vmodel : Entity
public string fullCode
{ get { return areaCode + "/" + vmCode; } }
[SugarColumn(IsIgnore = true)]
public Vmodel? parent { get; set; }
/// <summary>
/// 主键
/// </summary>
@@ -151,8 +146,8 @@ public partial class Vmodel : Entity
}
#endregion Properties
//private Dictionary<string, string>? _mapField2Prop = null;
//private Dictionary<string, string>? _mapProp2Field = null;
private Dictionary<string, VmDbProp>? _mapProps = null;
/// <summary>
/// 通过实体创建模型
/// </summary>
@@ -207,43 +202,13 @@ public partial class Vmodel : Entity
/// </summary>
/// <param name="propCode"></param>
/// <returns></returns>
public string? PropCodeToFieldCode(string propCode)
public string? PropToFieldCode(string propCode)
{
return dbProps.Where(a => a.code == propCode).Select(a => a.field).FirstOrDefault();
}
/// <summary>
/// 根据字段名获取属性名
/// </summary>
/// <param name="fieldCode"></param>
/// <returns></returns>
public string? FieldCodeToPropCode(string fieldCode)
{
return dbProps.Where(a => a.field == fieldCode).Select(a => a.code).FirstOrDefault();
}
/// <summary>
/// 属性代码转换为字段代码
/// </summary>
/// <param name="input"></param>
/// <param name="ignoreNotMapped"></param>
/// <returns></returns>
public DObject PropToField(DObject input, bool ignoreNotMapped = true)
{
DObject ret = new();
foreach (var item in input)
if(_mapProps == null)
{
var fcode = PropCodeToFieldCode(item.Key);
if (!string.IsNullOrEmpty(fcode))
{
ret.Add(fcode, item.Value);
}
else if (!ignoreNotMapped)
{
ret.Add(item.Key, item.Value);
}
_mapProps = dbProps.ToDictionary(a=>a.code);
}
return ret;
return _mapProps.GetOrDefault(propCode)?.field;
}
/// <summary>
@@ -252,214 +217,13 @@ public partial class Vmodel : Entity
/// <param name="input"></param>
/// <param name="ignoreNotMapped"></param>
/// <returns></returns>
public DObject FieldToProp(DObject input, bool ignoreNotMapped = true)
public VmDbProp? GetDbProp(string propCode)
{
DObject ret = new();
foreach (var item in input)
if (_mapProps == null)
{
var pcode = FieldCodeToPropCode(item.Key);
if (!string.IsNullOrEmpty(pcode))
{
ret.Add(pcode, item.Value);
}
else if (!ignoreNotMapped)
{
ret.Add(item.Key, item.Value);
}
_mapProps = dbProps.ToDictionary(a => a.code);
}
return ret;
}
/// <summary>
/// 获取查询字段的属性信息
/// </summary>
/// <param name="outputProps"></param>
/// <returns></returns>
public List<VmSelectProp> GetVmSelectProps(string? outputProps)
{
if (string.IsNullOrEmpty(outputProps) || outputProps == "*")
{
return dbProps.Select(a => new VmSelectProp { code = a.code, field = a.field }).ToList();
}
List<VmSelectProp> selProps = new();
var outputs = outputProps.Split(',').Distinct().ToList();
foreach (var propCode in outputs)
{
if (!propCode.Contains("."))
{
var fieldCode = PropCodeToFieldCode(propCode);
if (!string.IsNullOrEmpty(fieldCode))
{
selProps.Add(new VmSelectProp { code = propCode, field = fieldCode });
}
continue;
}
var codes = propCode.Split('.');
if (codes.Length != 2) continue;
if (codes[0] == VmSelectProp.MAIN_ALIES)
{
var fieldCode = PropCodeToFieldCode(propCode);
if (!string.IsNullOrEmpty(fieldCode))
{
selProps.Add(new VmSelectProp { code = propCode, field = fieldCode });
}
continue;
}
var navProp = navProps.FirstOrDefault(a => a.code == codes[0]);
if (navProp?.naviModel != null)
{
var fieldCode = navProp.naviModel.PropCodeToFieldCode(codes[1]);
if (!string.IsNullOrEmpty(fieldCode))
{
selProps.Add(new VmSelectProp { code = codes[1], field = fieldCode, navCode = codes[0], propType = ePropType.Navigate, navType = navProp.navType });
}
}
}
return selProps;
}
/// <summary>
/// 获取联表配置信息
/// </summary>
/// <param name="selProps"></param>
/// <returns></returns>
public List<JoinInfoParameter> GetJoinInfos(List<VmSelectProp> selProps)
{
var navigates = selProps.Where(a => a.propType == ePropType.Navigate).Select(a => a.navCode).Distinct().ToList();
List<JoinInfoParameter> joins = new();
foreach (var navCode in navigates)
{
if (navCode == VmSelectProp.MAIN_ALIES) continue;
var navProp = navProps.First(a => a.code == navCode);
if (navProp.naviModel == null || navProp.navType != eNavigateType.OneToOne) continue;
JoinInfoParameter join = new JoinInfoParameter { TableName = navProp.naviModel.tableName, ShortName = navCode, Type = JoinType.Left };
var fkField = navProp.naviModel.PropCodeToFieldCode(navProp.fkField);
var refField = navProp.refField;
if (navProp.refCode != VmSelectProp.MAIN_ALIES)
{
var refProp = navProps.First(a => a.code == navProp.refCode);
refField = refProp.naviModel!.PropCodeToFieldCode(navProp.refField);
}
join.Models = ObjectFuncModel.Create("Equals", $"{navCode}.{fkField}", $"{navProp.refCode}.{refField}");
joins.Add(join);
}
return joins;
}
/// <summary>
/// 转换为查询过滤条件
/// </summary>
/// <param name="filter"></param>
/// <returns></returns>
public List<IConditionalModel> GetConditionalModels(DObject? filter)
{
List<IConditionalModel> wheres = new List<IConditionalModel>();
if (filter == null) return wheres;
foreach (var item in filter)
{
VmDbProp? prop = null;
// TODO 按子表条件查询
if (item.Key.Contains("."))
{
var codes = item.Key.Split('.');
if (codes.Length >= 2)
{
var navProp = navProps.FirstOrDefault(a => a.code == codes[0]);
if (navProp != null && navProp.naviModel != null)
{
var dbProp = navProp.naviModel.dbProps.FirstOrDefault(a => a.code == codes[1]);
if (dbProp != null)
{
prop = new VmDbProp();
prop.field = codes[0] + "." + dbProp.field;
prop.csType = dbProp.csType;
}
}
}
}
else
{
prop = dbProps.FirstOrDefault(a => a.code == item.Key);
}
if (prop == null) continue;
if (item.Value is JArray val)
{
var op = val[0].ToString();
switch (op)
{
case "><":
wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThan, CSharpTypeName = prop.csType });
wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThan, CSharpTypeName = prop.csType });
break;
case ">=<":
wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThanOrEqual, CSharpTypeName = prop.csType });
wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThan, CSharpTypeName = prop.csType });
break;
case "><=":
wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThan, CSharpTypeName = prop.csType });
wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThanOrEqual, CSharpTypeName = prop.csType });
break;
case ">=<=":
wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThanOrEqual, CSharpTypeName = prop.csType });
wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThanOrEqual, CSharpTypeName = prop.csType });
break;
case "in":
wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val.Skip(1).ToString(), ConditionalType = ConditionalType.In, CSharpTypeName = prop.csType });
break;
default: op = string.Empty; break;
}
}
else
{
//if (item.Value == null) continue;
var conditionalType = ConditionalType.Equal;
string? value = item.Value?.ToString();
if (string.IsNullOrEmpty(value)) continue;
if (value.Length >= 2)
{
var op = value.Substring(0, 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 = prop.field, FieldValue = value, ConditionalType = conditionalType, CSharpTypeName = prop.csType });
}
}
return wheres;
}
/// <summary>
/// 转换为查询字段列表
/// </summary>
/// <param name="selProps"></param>
/// <returns></returns>
public List<SelectModel> GetSelectModels(List<VmSelectProp> selProps)
{
return selProps.Where(a => a.navType != eNavigateType.OneToMany && a.navType != eNavigateType.ManyToMany).Select(a => new SelectModel
{
FiledName = a.navCode + "." + a.field,
AsName = (a.navCode == VmSelectProp.MAIN_ALIES ? "" : a.navCode + "_") + a.code
}).ToList();
return _mapProps.GetOrDefault(propCode);
}
/// <summary>