diff --git a/XCode/Code/EntityBuilder.cs b/XCode/Code/EntityBuilder.cs index 1811a8ea8..93353bb84 100644 --- a/XCode/Code/EntityBuilder.cs +++ b/XCode/Code/EntityBuilder.cs @@ -20,6 +20,9 @@ public class EntityBuilder : ClassBuilder /// 使用缓存。默认true,标记为大数据的表不使用缓存 public Boolean UsingCache { get; set; } = true; + /// 数据规模字段。标识是否大数据表 + public IDataColumn? ScaleColumn { get; set; } + /// 所有表类型名。用于扩展属性 public IList AllTables { get; set; } = []; @@ -280,8 +283,12 @@ public class EntityBuilder : ClassBuilder protected override void Prepare() { // 标记为大数据的表不使用缓存 - var fi = Table.Columns.FirstOrDefault(e => e.DataScale.EqualIgnoreCase("time") || e.DataScale.StartsWithIgnoreCase("time:", "timeShard:")); - if (fi != null) UsingCache = false; + var column = Table.Columns.FirstOrDefault(e => e.DataScale.EqualIgnoreCase("time") || e.DataScale.StartsWithIgnoreCase("time:", "timeShard:")); + if (column != null) + { + UsingCache = false; + ScaleColumn = column; + } // 增加常用命名空间 AddNameSpace(); @@ -562,6 +569,12 @@ public class EntityBuilder : ClassBuilder WriteLine(); BuildExtendSearch(); + if (ScaleColumn != null) + { + WriteLine(); + BuildDelete(ScaleColumn); + } + WriteLine(); BuildFieldName(); } @@ -923,6 +936,47 @@ public class EntityBuilder : ClassBuilder WriteLine("#endregion"); } + /// 按时间删除数据 + protected virtual void BuildDelete(IDataColumn column) + { + WriteLine("#region 数据清理"); + + WriteLine("/// 清理指定时间段内的数据"); + WriteLine("/// 开始时间。未指定时清理小于指定时间的所有数据"); + WriteLine("/// 结束时间"); + WriteLine("/// 清理行数"); + WriteLine("public static Int32 DeleteWith(DateTime start, DateTime end)"); + WriteLine("{"); + { + // 分为时间、雪花Id、字符串三种 + var type = column.DataType; + if (type == typeof(DateTime)) + { + WriteLine("if (start == end) return Delete(_.{0} == start);", column.Name); + WriteLine(); + WriteLine("return Delete(_.{0}.Between(start, end));", column.Name); + } + else if (type == typeof(Int64)) + { + //WriteLine("var where = new WhereExpression()"); + //WriteLine("if (start.Year > 2000) where &= _.{0} >= Meta.Factory.Snow.GetId(start)", column.Name); + //WriteLine("if (end.Year > 2000) where &= _.{0} < Meta.Factory.Snow.GetId(end)", column.Name); + WriteLine("return Delete(_.{0}.Between(start, end, Meta.Factory.Snow));", column.Name); + } + else if (type == typeof(String)) + { + WriteLine("if (start == end) return Delete(_.{0} == start);", column.Name); + WriteLine(); + WriteLine("var where = new WhereExpression();"); + WriteLine("if (start.Year > 2000) where &= _.{0} >= start;", column.Name); + WriteLine("if (end.Year > 2000) where &= _.{0} < end;", column.Name); + WriteLine("return Delete(where);"); + } + } + WriteLine("}"); + + WriteLine("#endregion"); + } #endregion 数据类 #region 业务类 diff --git a/XUnitTest.XCode/Code/Entity/地区.Biz.cs b/XUnitTest.XCode/Code/Entity/地区.Biz.cs new file mode 100644 index 000000000..2c8a848aa --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/地区.Biz.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using NewLife.Log; +using NewLife.Model; +using NewLife.Reflection; +using NewLife.Threading; +using NewLife.Web; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; +using XCode.Membership; +using XCode.Shards; + +namespace XCode.Membership666; + +public partial class Area : Entity +{ + #region 对象操作 + static Area() + { + // 累加字段,生成 Update xx Set Count=Count+1234 Where xxx + //var df = Meta.Factory.AdditionalFields; + //df.Add(nameof(ParentID)); + + // 过滤器 UserModule、TimeModule、IPModule + Meta.Modules.Add(); + + // 实体缓存 + // var ec = Meta.Cache; + // ec.Expire = 60; + } + + /// 验证并修补数据,返回验证结果,或者通过抛出异常的方式提示验证失败。 + /// 添删改方法 + public override Boolean Valid(DataMethod method) + { + //if (method == DataMethod.Delete) return true; + // 如果没有脏数据,则不需要进行任何处理 + if (!HasDirty) return true; + + // 建议先调用基类方法,基类方法会做一些统一处理 + if (!base.Valid(method)) return false; + + // 在新插入数据或者修改了指定字段时进行修正 + + // 保留2位小数 + //Longitude = Math.Round(Longitude, 2); + //Latitude = Math.Round(Latitude, 2); + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateTime)]) CreateTime = DateTime.Now; + //if (!Dirtys[nameof(UpdateTime)]) UpdateTime = DateTime.Now; + + return true; + } + + ///// 首次连接数据库时初始化数据,仅用于实体类重载,用户不应该调用该方法 + //[EditorBrowsable(EditorBrowsableState.Never)] + //protected override void InitData() + //{ + // // InitData一般用于当数据表没有数据时添加一些默认数据,该实体类的任何第一次数据库操作都会触发该方法,默认异步调用 + // if (Meta.Session.Count > 0) return; + + // if (XTrace.Debug) XTrace.WriteLine("开始初始化Area[地区]数据……"); + + // var entity = new Area(); + // entity.ID = 0; + // entity.Name = "abc"; + // entity.FullName = "abc"; + // entity.ParentID = 0; + // entity.Level = 0; + // entity.Kind = "abc"; + // entity.English = "abc"; + // entity.PinYin = "abc"; + // entity.JianPin = "abc"; + // entity.TelCode = "abc"; + // entity.ZipCode = "abc"; + // entity.Longitude = 0.0; + // entity.Latitude = 0.0; + // entity.GeoHash = "abc"; + // entity.Enable = true; + // entity.Insert(); + + // if (XTrace.Debug) XTrace.WriteLine("完成初始化Area[地区]数据!"); + //} + + ///// 已重载。基类先调用Valid(true)验证数据,然后在事务保护内调用OnInsert + ///// + //public override Int32 Insert() + //{ + // return base.Insert(); + //} + + ///// 已重载。在事务保护范围内处理业务,位于Valid之后 + ///// + //protected override Int32 OnDelete() + //{ + // return base.OnDelete(); + //} + #endregion + + #region 扩展属性 + #endregion + + #region 高级查询 + /// 高级查询 + /// 名称 + /// 父级 + /// 拼音 + /// 简拼 + /// 地址编码。字符串前缀相同越多,地理距离越近,8位精度19米,6位610米 + /// 更新时间开始 + /// 更新时间结束 + /// 关键字 + /// 分页参数信息。可携带统计和数据权限扩展查询等信息 + /// 实体列表 + public static IList Search(String name, Int32 parentId, String pinYin, String jianPin, String geoHash, DateTime start, DateTime end, String key, PageParameter page) + { + var exp = new WhereExpression(); + + if (!name.IsNullOrEmpty()) exp &= _.Name == name; + if (parentId >= 0) exp &= _.ParentID == parentId; + if (!pinYin.IsNullOrEmpty()) exp &= _.PinYin == pinYin; + if (!jianPin.IsNullOrEmpty()) exp &= _.JianPin == jianPin; + if (!geoHash.IsNullOrEmpty()) exp &= _.GeoHash == geoHash; + exp &= _.UpdateTime.Between(start, end); + if (!key.IsNullOrEmpty()) exp &= _.Name.Contains(key) | _.FullName.Contains(key) | _.Kind.Contains(key) | _.English.Contains(key) | _.PinYin.Contains(key) | _.JianPin.Contains(key) | _.TelCode.Contains(key) | _.ZipCode.Contains(key) | _.GeoHash.Contains(key) | _.Remark.Contains(key); + + return FindAll(exp, page); + } + + // Select Count(Id) as Id,PinYin From Area Where CreateTime>'2020-01-24 00:00:00' Group By PinYin Order By Id Desc limit 20 + static readonly FieldCache _PinYinCache = new FieldCache(nameof(PinYin)) + { + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + }; + + /// 获取拼音列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + /// + public static IDictionary GetPinYinList() => _PinYinCache.FindAllName(); + + // Select Count(Id) as Id,JianPin From Area Where CreateTime>'2020-01-24 00:00:00' Group By JianPin Order By Id Desc limit 20 + static readonly FieldCache _JianPinCache = new FieldCache(nameof(JianPin)) + { + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + }; + + /// 获取简拼列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + /// + public static IDictionary GetJianPinList() => _JianPinCache.FindAllName(); + + // Select Count(Id) as Id,GeoHash From Area Where CreateTime>'2020-01-24 00:00:00' Group By GeoHash Order By Id Desc limit 20 + static readonly FieldCache _GeoHashCache = new FieldCache(nameof(GeoHash)) + { + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + }; + + /// 获取地址编码列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + /// + public static IDictionary GetGeoHashList() => _GeoHashCache.FindAllName(); + #endregion + + #region 业务操作 + public IArea ToModel() + { + var model = new Area(); + model.Copy(this); + + return model; + } + + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/地区.cs b/XUnitTest.XCode/Code/Entity/地区.cs new file mode 100644 index 000000000..b7a464712 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/地区.cs @@ -0,0 +1,465 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; + +namespace XCode.Membership666; + +/// 地区。行政区划数据,最高支持四级地址,9位数字 +[Serializable] +[DataObject] +[Description("地区。行政区划数据,最高支持四级地址,9位数字")] +[BindIndex("IX_Area_ParentID", false, "ParentID")] +[BindIndex("IX_Area_Name", false, "Name")] +[BindIndex("IX_Area_PinYin", false, "PinYin")] +[BindIndex("IX_Area_JianPin", false, "JianPin")] +[BindIndex("IX_Area_GeoHash", false, "GeoHash")] +[BindIndex("IX_Area_UpdateTime_ID", false, "UpdateTime,ID")] +[BindTable("Area", Description = "地区。行政区划数据,最高支持四级地址,9位数字", ConnName = "Membership", DbType = DatabaseType.None)] +public partial class Area : IArea, IEntity +{ + #region 属性 + private Int32 _ID; + /// 编码。行政区划编码 + [DisplayName("编码")] + [Description("编码。行政区划编码")] + [DataObjectField(true, false, false, 0)] + [BindColumn("ID", "编码。行政区划编码", "")] + public Int32 ID { get => _ID; set { if (OnPropertyChanging("ID", value)) { _ID = value; OnPropertyChanged("ID"); } } } + + private String? _Name; + /// 名称 + [DisplayName("名称")] + [Description("名称")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Name", "名称", "", Master = true)] + public String? Name { get => _Name; set { if (OnPropertyChanging("Name", value)) { _Name = value; OnPropertyChanged("Name"); } } } + + private String? _FullName; + /// 全名 + [DisplayName("全名")] + [Description("全名")] + [DataObjectField(false, false, true, 50)] + [BindColumn("FullName", "全名", "", Master = true)] + public String? FullName { get => _FullName; set { if (OnPropertyChanging("FullName", value)) { _FullName = value; OnPropertyChanged("FullName"); } } } + + private Int32 _ParentID; + /// 父级 + [DisplayName("父级")] + [Description("父级")] + [DataObjectField(false, false, false, 0)] + [BindColumn("ParentID", "父级", "")] + public Int32 ParentID { get => _ParentID; set { if (OnPropertyChanging("ParentID", value)) { _ParentID = value; OnPropertyChanged("ParentID"); } } } + + private Int32 _Level; + /// 层级 + [DisplayName("层级")] + [Description("层级")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Level", "层级", "")] + public Int32 Level { get => _Level; set { if (OnPropertyChanging("Level", value)) { _Level = value; OnPropertyChanged("Level"); } } } + + private String? _Kind; + /// 类型。省市县,自治州等 + [DisplayName("类型")] + [Description("类型。省市县,自治州等")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Kind", "类型。省市县,自治州等", "")] + public String? Kind { get => _Kind; set { if (OnPropertyChanging("Kind", value)) { _Kind = value; OnPropertyChanged("Kind"); } } } + + private String? _English; + /// 英文名 + [DisplayName("英文名")] + [Description("英文名")] + [DataObjectField(false, false, true, 50)] + [BindColumn("English", "英文名", "")] + public String? English { get => _English; set { if (OnPropertyChanging("English", value)) { _English = value; OnPropertyChanged("English"); } } } + + private String? _PinYin; + /// 拼音 + [DisplayName("拼音")] + [Description("拼音")] + [DataObjectField(false, false, true, 50)] + [BindColumn("PinYin", "拼音", "")] + public String? PinYin { get => _PinYin; set { if (OnPropertyChanging("PinYin", value)) { _PinYin = value; OnPropertyChanged("PinYin"); } } } + + private String? _JianPin; + /// 简拼 + [DisplayName("简拼")] + [Description("简拼")] + [DataObjectField(false, false, true, 50)] + [BindColumn("JianPin", "简拼", "")] + public String? JianPin { get => _JianPin; set { if (OnPropertyChanging("JianPin", value)) { _JianPin = value; OnPropertyChanged("JianPin"); } } } + + private String? _TelCode; + /// 区号。电话区号 + [DisplayName("区号")] + [Description("区号。电话区号")] + [DataObjectField(false, false, true, 50)] + [BindColumn("TelCode", "区号。电话区号", "")] + public String? TelCode { get => _TelCode; set { if (OnPropertyChanging("TelCode", value)) { _TelCode = value; OnPropertyChanged("TelCode"); } } } + + private String? _ZipCode; + /// 邮编。邮政编码 + [DisplayName("邮编")] + [Description("邮编。邮政编码")] + [DataObjectField(false, false, true, 50)] + [BindColumn("ZipCode", "邮编。邮政编码", "")] + public String? ZipCode { get => _ZipCode; set { if (OnPropertyChanging("ZipCode", value)) { _ZipCode = value; OnPropertyChanged("ZipCode"); } } } + + private Double _Longitude; + /// 经度 + [DisplayName("经度")] + [Description("经度")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Longitude", "经度", "")] + public Double Longitude { get => _Longitude; set { if (OnPropertyChanging("Longitude", value)) { _Longitude = value; OnPropertyChanged("Longitude"); } } } + + private Double _Latitude; + /// 纬度 + [DisplayName("纬度")] + [Description("纬度")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Latitude", "纬度", "")] + public Double Latitude { get => _Latitude; set { if (OnPropertyChanging("Latitude", value)) { _Latitude = value; OnPropertyChanged("Latitude"); } } } + + private String? _GeoHash; + /// 地址编码。字符串前缀相同越多,地理距离越近,8位精度19米,6位610米 + [DisplayName("地址编码")] + [Description("地址编码。字符串前缀相同越多,地理距离越近,8位精度19米,6位610米")] + [DataObjectField(false, false, true, 50)] + [BindColumn("GeoHash", "地址编码。字符串前缀相同越多,地理距离越近,8位精度19米,6位610米", "")] + public String? GeoHash { get => _GeoHash; set { if (OnPropertyChanging("GeoHash", value)) { _GeoHash = value; OnPropertyChanged("GeoHash"); } } } + + private Boolean _Enable; + /// 启用 + [DisplayName("启用")] + [Description("启用")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Enable", "启用", "")] + public Boolean Enable { get => _Enable; set { if (OnPropertyChanging("Enable", value)) { _Enable = value; OnPropertyChanged("Enable"); } } } + + private DateTime _CreateTime; + /// 创建时间 + [Category("扩展")] + [DisplayName("创建时间")] + [Description("创建时间")] + [DataObjectField(false, false, true, 0)] + [BindColumn("CreateTime", "创建时间", "")] + public DateTime CreateTime { get => _CreateTime; set { if (OnPropertyChanging("CreateTime", value)) { _CreateTime = value; OnPropertyChanged("CreateTime"); } } } + + private DateTime _UpdateTime; + /// 更新时间 + [Category("扩展")] + [DisplayName("更新时间")] + [Description("更新时间")] + [DataObjectField(false, false, true, 0)] + [BindColumn("UpdateTime", "更新时间", "")] + public DateTime UpdateTime { get => _UpdateTime; set { if (OnPropertyChanging("UpdateTime", value)) { _UpdateTime = value; OnPropertyChanged("UpdateTime"); } } } + + private String? _Remark; + /// 备注 + [Category("扩展")] + [DisplayName("备注")] + [Description("备注")] + [DataObjectField(false, false, true, 500)] + [BindColumn("Remark", "备注", "")] + public String? Remark { get => _Remark; set { if (OnPropertyChanging("Remark", value)) { _Remark = value; OnPropertyChanged("Remark"); } } } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IArea model) + { + ID = model.ID; + Name = model.Name; + FullName = model.FullName; + ParentID = model.ParentID; + Level = model.Level; + Kind = model.Kind; + English = model.English; + PinYin = model.PinYin; + JianPin = model.JianPin; + TelCode = model.TelCode; + ZipCode = model.ZipCode; + Longitude = model.Longitude; + Latitude = model.Latitude; + GeoHash = model.GeoHash; + Enable = model.Enable; + CreateTime = model.CreateTime; + UpdateTime = model.UpdateTime; + Remark = model.Remark; + } + #endregion + + #region 获取/设置 字段值 + /// 获取/设置 字段值 + /// 字段名 + /// + public override Object? this[String name] + { + get => name switch + { + "ID" => _ID, + "Name" => _Name, + "FullName" => _FullName, + "ParentID" => _ParentID, + "Level" => _Level, + "Kind" => _Kind, + "English" => _English, + "PinYin" => _PinYin, + "JianPin" => _JianPin, + "TelCode" => _TelCode, + "ZipCode" => _ZipCode, + "Longitude" => _Longitude, + "Latitude" => _Latitude, + "GeoHash" => _GeoHash, + "Enable" => _Enable, + "CreateTime" => _CreateTime, + "UpdateTime" => _UpdateTime, + "Remark" => _Remark, + _ => base[name] + }; + set + { + switch (name) + { + case "ID": _ID = value.ToInt(); break; + case "Name": _Name = Convert.ToString(value); break; + case "FullName": _FullName = Convert.ToString(value); break; + case "ParentID": _ParentID = value.ToInt(); break; + case "Level": _Level = value.ToInt(); break; + case "Kind": _Kind = Convert.ToString(value); break; + case "English": _English = Convert.ToString(value); break; + case "PinYin": _PinYin = Convert.ToString(value); break; + case "JianPin": _JianPin = Convert.ToString(value); break; + case "TelCode": _TelCode = Convert.ToString(value); break; + case "ZipCode": _ZipCode = Convert.ToString(value); break; + case "Longitude": _Longitude = value.ToDouble(); break; + case "Latitude": _Latitude = value.ToDouble(); break; + case "GeoHash": _GeoHash = Convert.ToString(value); break; + case "Enable": _Enable = value.ToBoolean(); break; + case "CreateTime": _CreateTime = value.ToDateTime(); break; + case "UpdateTime": _UpdateTime = value.ToDateTime(); break; + case "Remark": _Remark = Convert.ToString(value); break; + default: base[name] = value; break; + } + } + } + #endregion + + #region 关联映射 + #endregion + + #region 扩展查询 + /// 根据编码查找 + /// 编码 + /// 实体对象 + public static Area FindByID(Int32 id) + { + if (id < 0) return null; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.ID == id); + + // 单对象缓存 + return Meta.SingleCache[id]; + + //return Find(_.ID == id); + } + + /// 根据父级查找 + /// 父级 + /// 实体列表 + public static IList FindAllByParentID(Int32 parentId) + { + if (parentId < 0) return []; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.ParentID == parentId); + + return FindAll(_.ParentID == parentId); + } + + /// 根据名称查找 + /// 名称 + /// 实体列表 + public static IList FindAllByName(String name) + { + if (name.IsNullOrEmpty()) return []; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.Name.EqualIgnoreCase(name)); + + return FindAll(_.Name == name); + } + + /// 根据拼音查找 + /// 拼音 + /// 实体列表 + public static IList FindAllByPinYin(String pinYin) + { + if (pinYin.IsNullOrEmpty()) return []; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.PinYin.EqualIgnoreCase(pinYin)); + + return FindAll(_.PinYin == pinYin); + } + + /// 根据简拼查找 + /// 简拼 + /// 实体列表 + public static IList FindAllByJianPin(String jianPin) + { + if (jianPin.IsNullOrEmpty()) return []; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.JianPin.EqualIgnoreCase(jianPin)); + + return FindAll(_.JianPin == jianPin); + } + + /// 根据地址编码查找 + /// 地址编码 + /// 实体列表 + public static IList FindAllByGeoHash(String geoHash) + { + if (geoHash.IsNullOrEmpty()) return []; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.GeoHash.EqualIgnoreCase(geoHash)); + + return FindAll(_.GeoHash == geoHash); + } + #endregion + + #region 字段名 + /// 取得地区字段信息的快捷方式 + public partial class _ + { + /// 编码。行政区划编码 + public static readonly Field ID = FindByName("ID"); + + /// 名称 + public static readonly Field Name = FindByName("Name"); + + /// 全名 + public static readonly Field FullName = FindByName("FullName"); + + /// 父级 + public static readonly Field ParentID = FindByName("ParentID"); + + /// 层级 + public static readonly Field Level = FindByName("Level"); + + /// 类型。省市县,自治州等 + public static readonly Field Kind = FindByName("Kind"); + + /// 英文名 + public static readonly Field English = FindByName("English"); + + /// 拼音 + public static readonly Field PinYin = FindByName("PinYin"); + + /// 简拼 + public static readonly Field JianPin = FindByName("JianPin"); + + /// 区号。电话区号 + public static readonly Field TelCode = FindByName("TelCode"); + + /// 邮编。邮政编码 + public static readonly Field ZipCode = FindByName("ZipCode"); + + /// 经度 + public static readonly Field Longitude = FindByName("Longitude"); + + /// 纬度 + public static readonly Field Latitude = FindByName("Latitude"); + + /// 地址编码。字符串前缀相同越多,地理距离越近,8位精度19米,6位610米 + public static readonly Field GeoHash = FindByName("GeoHash"); + + /// 启用 + public static readonly Field Enable = FindByName("Enable"); + + /// 创建时间 + public static readonly Field CreateTime = FindByName("CreateTime"); + + /// 更新时间 + public static readonly Field UpdateTime = FindByName("UpdateTime"); + + /// 备注 + public static readonly Field Remark = FindByName("Remark"); + + static Field FindByName(String name) => Meta.Table.FindByName(name); + } + + /// 取得地区字段名称的快捷方式 + public partial class __ + { + /// 编码。行政区划编码 + public const String ID = "ID"; + + /// 名称 + public const String Name = "Name"; + + /// 全名 + public const String FullName = "FullName"; + + /// 父级 + public const String ParentID = "ParentID"; + + /// 层级 + public const String Level = "Level"; + + /// 类型。省市县,自治州等 + public const String Kind = "Kind"; + + /// 英文名 + public const String English = "English"; + + /// 拼音 + public const String PinYin = "PinYin"; + + /// 简拼 + public const String JianPin = "JianPin"; + + /// 区号。电话区号 + public const String TelCode = "TelCode"; + + /// 邮编。邮政编码 + public const String ZipCode = "ZipCode"; + + /// 经度 + public const String Longitude = "Longitude"; + + /// 纬度 + public const String Latitude = "Latitude"; + + /// 地址编码。字符串前缀相同越多,地理距离越近,8位精度19米,6位610米 + public const String GeoHash = "GeoHash"; + + /// 启用 + public const String Enable = "Enable"; + + /// 创建时间 + public const String CreateTime = "CreateTime"; + + /// 更新时间 + public const String UpdateTime = "UpdateTime"; + + /// 备注 + public const String Remark = "Remark"; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/字典参数.Biz.cs b/XUnitTest.XCode/Code/Entity/字典参数.Biz.cs new file mode 100644 index 000000000..f58df58b4 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/字典参数.Biz.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using NewLife.Log; +using NewLife.Model; +using NewLife.Reflection; +using NewLife.Threading; +using NewLife.Web; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; +using XCode.Membership; +using XCode.Shards; + +namespace XCode.Membership666; + +public partial class Parameter : Entity +{ + #region 对象操作 + static Parameter() + { + // 累加字段,生成 Update xx Set Count=Count+1234 Where xxx + //var df = Meta.Factory.AdditionalFields; + //df.Add(nameof(UserID)); + + // 过滤器 UserModule、TimeModule、IPModule + Meta.Modules.Add(new UserModule { AllowEmpty = false }); + Meta.Modules.Add(); + Meta.Modules.Add(new IPModule { AllowEmpty = false }); + + // 实体缓存 + // var ec = Meta.Cache; + // ec.Expire = 60; + } + + /// 验证并修补数据,返回验证结果,或者通过抛出异常的方式提示验证失败。 + /// 添删改方法 + public override Boolean Valid(DataMethod method) + { + //if (method == DataMethod.Delete) return true; + // 如果没有脏数据,则不需要进行任何处理 + if (!HasDirty) return true; + + // 建议先调用基类方法,基类方法会做一些统一处理 + if (!base.Valid(method)) return false; + + // 在新插入数据或者修改了指定字段时进行修正 + + // 保留2位小数 + //Ex3 = Math.Round(Ex3, 2); + + // 处理当前已登录用户信息,可以由UserModule过滤器代劳 + /*var user = ManageProvider.User; + if (user != null) + { + if (method == DataMethod.Insert && !Dirtys[nameof(CreateUserID)]) CreateUserID = user.ID; + if (!Dirtys[nameof(UpdateUserID)]) UpdateUserID = user.ID; + }*/ + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateTime)]) CreateTime = DateTime.Now; + //if (!Dirtys[nameof(UpdateTime)]) UpdateTime = DateTime.Now; + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateIP)]) CreateIP = ManageProvider.UserHost; + //if (!Dirtys[nameof(UpdateIP)]) UpdateIP = ManageProvider.UserHost; + + // 检查唯一索引 + // CheckExist(method == DataMethod.Insert, nameof(UserID), nameof(Category), nameof(Name)); + + return true; + } + + ///// 首次连接数据库时初始化数据,仅用于实体类重载,用户不应该调用该方法 + //[EditorBrowsable(EditorBrowsableState.Never)] + //protected override void InitData() + //{ + // // InitData一般用于当数据表没有数据时添加一些默认数据,该实体类的任何第一次数据库操作都会触发该方法,默认异步调用 + // if (Meta.Session.Count > 0) return; + + // if (XTrace.Debug) XTrace.WriteLine("开始初始化Parameter[字典参数]数据……"); + + // var entity = new Parameter(); + // entity.UserID = 0; + // entity.Category = "abc"; + // entity.Name = "abc"; + // entity.Value = "abc"; + // entity.LongValue = "abc"; + // entity.Kind = 0; + // entity.Enable = true; + // entity.Ex1 = 0; + // entity.Ex2 = 0.0; + // entity.Ex3 = 0.0; + // entity.Ex4 = "abc"; + // entity.Ex5 = "abc"; + // entity.Ex6 = "abc"; + // entity.Insert(); + + // if (XTrace.Debug) XTrace.WriteLine("完成初始化Parameter[字典参数]数据!"); + //} + + ///// 已重载。基类先调用Valid(true)验证数据,然后在事务保护内调用OnInsert + ///// + //public override Int32 Insert() + //{ + // return base.Insert(); + //} + + ///// 已重载。在事务保护范围内处理业务,位于Valid之后 + ///// + //protected override Int32 OnDelete() + //{ + // return base.OnDelete(); + //} + #endregion + + #region 扩展属性 + #endregion + + #region 高级查询 + /// 高级查询 + /// 用户。按用户区分参数,用户0表示系统级 + /// 类别 + /// 名称 + /// 更新时间开始 + /// 更新时间结束 + /// 关键字 + /// 分页参数信息。可携带统计和数据权限扩展查询等信息 + /// 实体列表 + public static IList Search(Int32 userId, String category, String name, DateTime start, DateTime end, String key, PageParameter page) + { + var exp = new WhereExpression(); + + if (userId >= 0) exp &= _.UserID == userId; + if (!category.IsNullOrEmpty()) exp &= _.Category == category; + if (!name.IsNullOrEmpty()) exp &= _.Name == name; + exp &= _.UpdateTime.Between(start, end); + if (!key.IsNullOrEmpty()) exp &= _.Category.Contains(key) | _.Name.Contains(key) | _.Value.Contains(key) | _.LongValue.Contains(key) | _.Ex4.Contains(key) | _.Ex5.Contains(key) | _.Ex6.Contains(key) | _.CreateUser.Contains(key) | _.CreateIP.Contains(key) | _.UpdateUser.Contains(key) | _.UpdateIP.Contains(key) | _.Remark.Contains(key); + + return FindAll(exp, page); + } + + // Select Count(ID) as ID,Category From Parameter Where CreateTime>'2020-01-24 00:00:00' Group By Category Order By ID Desc limit 20 + static readonly FieldCache _CategoryCache = new FieldCache(nameof(Category)) + { + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + }; + + /// 获取类别列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + /// + public static IDictionary GetCategoryList() => _CategoryCache.FindAllName(); + #endregion + + #region 业务操作 + public IParameter ToModel() + { + var model = new Parameter(); + model.Copy(this); + + return model; + } + + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/字典参数.cs b/XUnitTest.XCode/Code/Entity/字典参数.cs new file mode 100644 index 000000000..fecc252e8 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/字典参数.cs @@ -0,0 +1,534 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; + +namespace XCode.Membership666; + +/// 字典参数 +[Serializable] +[DataObject] +[Description("字典参数")] +[BindIndex("IU_Parameter_UserID_Category_Name", true, "UserID,Category,Name")] +[BindIndex("IX_Parameter_Category_Name", false, "Category,Name")] +[BindIndex("IX_Parameter_UpdateTime", false, "UpdateTime")] +[BindTable("Parameter", Description = "字典参数", ConnName = "Membership", DbType = DatabaseType.None)] +public partial class Parameter : IParameter, IEntity +{ + #region 属性 + private Int32 _ID; + /// 编号 + [DisplayName("编号")] + [Description("编号")] + [DataObjectField(true, true, false, 0)] + [BindColumn("ID", "编号", "")] + public Int32 ID { get => _ID; set { if (OnPropertyChanging("ID", value)) { _ID = value; OnPropertyChanged("ID"); } } } + + private Int32 _UserID; + /// 用户。按用户区分参数,用户0表示系统级 + [DisplayName("用户")] + [Description("用户。按用户区分参数,用户0表示系统级")] + [DataObjectField(false, false, false, 0)] + [BindColumn("UserID", "用户。按用户区分参数,用户0表示系统级", "")] + public Int32 UserID { get => _UserID; set { if (OnPropertyChanging("UserID", value)) { _UserID = value; OnPropertyChanged("UserID"); } } } + + private String? _Category; + /// 类别 + [DisplayName("类别")] + [Description("类别")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Category", "类别", "")] + public String? Category { get => _Category; set { if (OnPropertyChanging("Category", value)) { _Category = value; OnPropertyChanged("Category"); } } } + + private String? _Name; + /// 名称 + [DisplayName("名称")] + [Description("名称")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Name", "名称", "", Master = true)] + public String? Name { get => _Name; set { if (OnPropertyChanging("Name", value)) { _Name = value; OnPropertyChanged("Name"); } } } + + private String? _Value; + /// 数值 + [DisplayName("数值")] + [Description("数值")] + [DataObjectField(false, false, true, 200)] + [BindColumn("Value", "数值", "")] + public String? Value { get => _Value; set { if (OnPropertyChanging("Value", value)) { _Value = value; OnPropertyChanged("Value"); } } } + + private String? _LongValue; + /// 长数值 + [DisplayName("长数值")] + [Description("长数值")] + [DataObjectField(false, false, true, 2000)] + [BindColumn("LongValue", "长数值", "")] + public String? LongValue { get => _LongValue; set { if (OnPropertyChanging("LongValue", value)) { _LongValue = value; OnPropertyChanged("LongValue"); } } } + + private XCode.Membership.ParameterKinds _Kind; + /// 种类。0普通,21列表,22名值 + [DisplayName("种类")] + [Description("种类。0普通,21列表,22名值")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Kind", "种类。0普通,21列表,22名值", "")] + public XCode.Membership.ParameterKinds Kind { get => _Kind; set { if (OnPropertyChanging("Kind", value)) { _Kind = value; OnPropertyChanged("Kind"); } } } + + private Boolean _Enable; + /// 启用 + [DisplayName("启用")] + [Description("启用")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Enable", "启用", "")] + public Boolean Enable { get => _Enable; set { if (OnPropertyChanging("Enable", value)) { _Enable = value; OnPropertyChanged("Enable"); } } } + + private Int32 _Ex1; + /// 扩展1 + [Category("扩展")] + [DisplayName("扩展1")] + [Description("扩展1")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex1", "扩展1", "")] + public Int32 Ex1 { get => _Ex1; set { if (OnPropertyChanging("Ex1", value)) { _Ex1 = value; OnPropertyChanged("Ex1"); } } } + + private Decimal _Ex2; + /// 扩展2 + [Category("扩展")] + [DisplayName("扩展2")] + [Description("扩展2")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex2", "扩展2", "", Precision = 19, Scale = 4)] + public Decimal Ex2 { get => _Ex2; set { if (OnPropertyChanging("Ex2", value)) { _Ex2 = value; OnPropertyChanged("Ex2"); } } } + + private Double _Ex3; + /// 扩展3 + [Category("扩展")] + [DisplayName("扩展3")] + [Description("扩展3")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex3", "扩展3", "")] + public Double Ex3 { get => _Ex3; set { if (OnPropertyChanging("Ex3", value)) { _Ex3 = value; OnPropertyChanged("Ex3"); } } } + + private String? _Ex4; + /// 扩展4 + [Category("扩展")] + [DisplayName("扩展4")] + [Description("扩展4")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex4", "扩展4", "")] + public String? Ex4 { get => _Ex4; set { if (OnPropertyChanging("Ex4", value)) { _Ex4 = value; OnPropertyChanged("Ex4"); } } } + + private String? _Ex5; + /// 扩展5 + [Category("扩展")] + [DisplayName("扩展5")] + [Description("扩展5")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex5", "扩展5", "")] + public String? Ex5 { get => _Ex5; set { if (OnPropertyChanging("Ex5", value)) { _Ex5 = value; OnPropertyChanged("Ex5"); } } } + + private String? _Ex6; + /// 扩展6 + [Category("扩展")] + [DisplayName("扩展6")] + [Description("扩展6")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex6", "扩展6", "")] + public String? Ex6 { get => _Ex6; set { if (OnPropertyChanging("Ex6", value)) { _Ex6 = value; OnPropertyChanged("Ex6"); } } } + + private String? _CreateUser; + /// 创建者 + [Category("扩展")] + [DisplayName("创建者")] + [Description("创建者")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateUser", "创建者", "")] + public String? CreateUser { get => _CreateUser; set { if (OnPropertyChanging("CreateUser", value)) { _CreateUser = value; OnPropertyChanged("CreateUser"); } } } + + private Int32 _CreateUserID; + /// 创建用户 + [Category("扩展")] + [DisplayName("创建用户")] + [Description("创建用户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateUserID", "创建用户", "")] + public Int32 CreateUserID { get => _CreateUserID; set { if (OnPropertyChanging("CreateUserID", value)) { _CreateUserID = value; OnPropertyChanged("CreateUserID"); } } } + + private String? _CreateIP; + /// 创建地址 + [Category("扩展")] + [DisplayName("创建地址")] + [Description("创建地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateIP", "创建地址", "")] + public String? CreateIP { get => _CreateIP; set { if (OnPropertyChanging("CreateIP", value)) { _CreateIP = value; OnPropertyChanged("CreateIP"); } } } + + private DateTime _CreateTime; + /// 创建时间 + [Category("扩展")] + [DisplayName("创建时间")] + [Description("创建时间")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateTime", "创建时间", "")] + public DateTime CreateTime { get => _CreateTime; set { if (OnPropertyChanging("CreateTime", value)) { _CreateTime = value; OnPropertyChanged("CreateTime"); } } } + + private String? _UpdateUser; + /// 更新者 + [Category("扩展")] + [DisplayName("更新者")] + [Description("更新者")] + [DataObjectField(false, false, true, 50)] + [BindColumn("UpdateUser", "更新者", "")] + public String? UpdateUser { get => _UpdateUser; set { if (OnPropertyChanging("UpdateUser", value)) { _UpdateUser = value; OnPropertyChanged("UpdateUser"); } } } + + private Int32 _UpdateUserID; + /// 更新用户 + [Category("扩展")] + [DisplayName("更新用户")] + [Description("更新用户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("UpdateUserID", "更新用户", "")] + public Int32 UpdateUserID { get => _UpdateUserID; set { if (OnPropertyChanging("UpdateUserID", value)) { _UpdateUserID = value; OnPropertyChanged("UpdateUserID"); } } } + + private String? _UpdateIP; + /// 更新地址 + [Category("扩展")] + [DisplayName("更新地址")] + [Description("更新地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("UpdateIP", "更新地址", "")] + public String? UpdateIP { get => _UpdateIP; set { if (OnPropertyChanging("UpdateIP", value)) { _UpdateIP = value; OnPropertyChanged("UpdateIP"); } } } + + private DateTime _UpdateTime; + /// 更新时间 + [Category("扩展")] + [DisplayName("更新时间")] + [Description("更新时间")] + [DataObjectField(false, false, false, 0)] + [BindColumn("UpdateTime", "更新时间", "")] + public DateTime UpdateTime { get => _UpdateTime; set { if (OnPropertyChanging("UpdateTime", value)) { _UpdateTime = value; OnPropertyChanged("UpdateTime"); } } } + + private String? _Remark; + /// 备注 + [Category("扩展")] + [DisplayName("备注")] + [Description("备注")] + [DataObjectField(false, false, true, 500)] + [BindColumn("Remark", "备注", "")] + public String? Remark { get => _Remark; set { if (OnPropertyChanging("Remark", value)) { _Remark = value; OnPropertyChanged("Remark"); } } } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IParameter model) + { + ID = model.ID; + UserID = model.UserID; + Category = model.Category; + Name = model.Name; + Value = model.Value; + LongValue = model.LongValue; + Kind = model.Kind; + Enable = model.Enable; + Ex1 = model.Ex1; + Ex2 = model.Ex2; + Ex3 = model.Ex3; + Ex4 = model.Ex4; + Ex5 = model.Ex5; + Ex6 = model.Ex6; + CreateUser = model.CreateUser; + CreateUserID = model.CreateUserID; + CreateIP = model.CreateIP; + CreateTime = model.CreateTime; + UpdateUser = model.UpdateUser; + UpdateUserID = model.UpdateUserID; + UpdateIP = model.UpdateIP; + UpdateTime = model.UpdateTime; + Remark = model.Remark; + } + #endregion + + #region 获取/设置 字段值 + /// 获取/设置 字段值 + /// 字段名 + /// + public override Object? this[String name] + { + get => name switch + { + "ID" => _ID, + "UserID" => _UserID, + "Category" => _Category, + "Name" => _Name, + "Value" => _Value, + "LongValue" => _LongValue, + "Kind" => _Kind, + "Enable" => _Enable, + "Ex1" => _Ex1, + "Ex2" => _Ex2, + "Ex3" => _Ex3, + "Ex4" => _Ex4, + "Ex5" => _Ex5, + "Ex6" => _Ex6, + "CreateUser" => _CreateUser, + "CreateUserID" => _CreateUserID, + "CreateIP" => _CreateIP, + "CreateTime" => _CreateTime, + "UpdateUser" => _UpdateUser, + "UpdateUserID" => _UpdateUserID, + "UpdateIP" => _UpdateIP, + "UpdateTime" => _UpdateTime, + "Remark" => _Remark, + _ => base[name] + }; + set + { + switch (name) + { + case "ID": _ID = value.ToInt(); break; + case "UserID": _UserID = value.ToInt(); break; + case "Category": _Category = Convert.ToString(value); break; + case "Name": _Name = Convert.ToString(value); break; + case "Value": _Value = Convert.ToString(value); break; + case "LongValue": _LongValue = Convert.ToString(value); break; + case "Kind": _Kind = (XCode.Membership.ParameterKinds)value.ToInt(); break; + case "Enable": _Enable = value.ToBoolean(); break; + case "Ex1": _Ex1 = value.ToInt(); break; + case "Ex2": _Ex2 = Convert.ToDecimal(value); break; + case "Ex3": _Ex3 = value.ToDouble(); break; + case "Ex4": _Ex4 = Convert.ToString(value); break; + case "Ex5": _Ex5 = Convert.ToString(value); break; + case "Ex6": _Ex6 = Convert.ToString(value); break; + case "CreateUser": _CreateUser = Convert.ToString(value); break; + case "CreateUserID": _CreateUserID = value.ToInt(); break; + case "CreateIP": _CreateIP = Convert.ToString(value); break; + case "CreateTime": _CreateTime = value.ToDateTime(); break; + case "UpdateUser": _UpdateUser = Convert.ToString(value); break; + case "UpdateUserID": _UpdateUserID = value.ToInt(); break; + case "UpdateIP": _UpdateIP = Convert.ToString(value); break; + case "UpdateTime": _UpdateTime = value.ToDateTime(); break; + case "Remark": _Remark = Convert.ToString(value); break; + default: base[name] = value; break; + } + } + } + #endregion + + #region 关联映射 + /// 用户 + [XmlIgnore, IgnoreDataMember, ScriptIgnore] + public User? User => Extends.Get(nameof(User), k => User.FindByID(UserID)); + + /// 用户 + [Map(nameof(UserID), typeof(User), "ID")] + public String? UserName => User?.ToString(); + + #endregion + + #region 扩展查询 + /// 根据编号查找 + /// 编号 + /// 实体对象 + public static Parameter FindByID(Int32 id) + { + if (id < 0) return null; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.ID == id); + + // 单对象缓存 + return Meta.SingleCache[id]; + + //return Find(_.ID == id); + } + + /// 根据用户、类别、名称查找 + /// 用户 + /// 类别 + /// 名称 + /// 实体对象 + public static Parameter FindByUserIDAndCategoryAndName(Int32 userId, String category, String name) + { + if (userId < 0) return null; + if (category.IsNullOrEmpty()) return null; + if (name.IsNullOrEmpty()) return null; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.UserID == userId && e.Category.EqualIgnoreCase(category) && e.Name.EqualIgnoreCase(name)); + + return Find(_.UserID == userId & _.Category == category & _.Name == name); + } + + /// 根据类别、名称查找 + /// 类别 + /// 名称 + /// 实体列表 + public static IList FindAllByCategoryAndName(String category, String name) + { + if (category.IsNullOrEmpty()) return []; + if (name.IsNullOrEmpty()) return []; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.Category.EqualIgnoreCase(category) && e.Name.EqualIgnoreCase(name)); + + return FindAll(_.Category == category & _.Name == name); + } + #endregion + + #region 字段名 + /// 取得字典参数字段信息的快捷方式 + public partial class _ + { + /// 编号 + public static readonly Field ID = FindByName("ID"); + + /// 用户。按用户区分参数,用户0表示系统级 + public static readonly Field UserID = FindByName("UserID"); + + /// 类别 + public static readonly Field Category = FindByName("Category"); + + /// 名称 + public static readonly Field Name = FindByName("Name"); + + /// 数值 + public static readonly Field Value = FindByName("Value"); + + /// 长数值 + public static readonly Field LongValue = FindByName("LongValue"); + + /// 种类。0普通,21列表,22名值 + public static readonly Field Kind = FindByName("Kind"); + + /// 启用 + public static readonly Field Enable = FindByName("Enable"); + + /// 扩展1 + public static readonly Field Ex1 = FindByName("Ex1"); + + /// 扩展2 + public static readonly Field Ex2 = FindByName("Ex2"); + + /// 扩展3 + public static readonly Field Ex3 = FindByName("Ex3"); + + /// 扩展4 + public static readonly Field Ex4 = FindByName("Ex4"); + + /// 扩展5 + public static readonly Field Ex5 = FindByName("Ex5"); + + /// 扩展6 + public static readonly Field Ex6 = FindByName("Ex6"); + + /// 创建者 + public static readonly Field CreateUser = FindByName("CreateUser"); + + /// 创建用户 + public static readonly Field CreateUserID = FindByName("CreateUserID"); + + /// 创建地址 + public static readonly Field CreateIP = FindByName("CreateIP"); + + /// 创建时间 + public static readonly Field CreateTime = FindByName("CreateTime"); + + /// 更新者 + public static readonly Field UpdateUser = FindByName("UpdateUser"); + + /// 更新用户 + public static readonly Field UpdateUserID = FindByName("UpdateUserID"); + + /// 更新地址 + public static readonly Field UpdateIP = FindByName("UpdateIP"); + + /// 更新时间 + public static readonly Field UpdateTime = FindByName("UpdateTime"); + + /// 备注 + public static readonly Field Remark = FindByName("Remark"); + + static Field FindByName(String name) => Meta.Table.FindByName(name); + } + + /// 取得字典参数字段名称的快捷方式 + public partial class __ + { + /// 编号 + public const String ID = "ID"; + + /// 用户。按用户区分参数,用户0表示系统级 + public const String UserID = "UserID"; + + /// 类别 + public const String Category = "Category"; + + /// 名称 + public const String Name = "Name"; + + /// 数值 + public const String Value = "Value"; + + /// 长数值 + public const String LongValue = "LongValue"; + + /// 种类。0普通,21列表,22名值 + public const String Kind = "Kind"; + + /// 启用 + public const String Enable = "Enable"; + + /// 扩展1 + public const String Ex1 = "Ex1"; + + /// 扩展2 + public const String Ex2 = "Ex2"; + + /// 扩展3 + public const String Ex3 = "Ex3"; + + /// 扩展4 + public const String Ex4 = "Ex4"; + + /// 扩展5 + public const String Ex5 = "Ex5"; + + /// 扩展6 + public const String Ex6 = "Ex6"; + + /// 创建者 + public const String CreateUser = "CreateUser"; + + /// 创建用户 + public const String CreateUserID = "CreateUserID"; + + /// 创建地址 + public const String CreateIP = "CreateIP"; + + /// 创建时间 + public const String CreateTime = "CreateTime"; + + /// 更新者 + public const String UpdateUser = "UpdateUser"; + + /// 更新用户 + public const String UpdateUserID = "UpdateUserID"; + + /// 更新地址 + public const String UpdateIP = "UpdateIP"; + + /// 更新时间 + public const String UpdateTime = "UpdateTime"; + + /// 备注 + public const String Remark = "Remark"; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/成员日志.Biz.cs b/XUnitTest.XCode/Code/Entity/成员日志.Biz.cs new file mode 100644 index 000000000..c2a8e0a6f --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/成员日志.Biz.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using NewLife.Log; +using NewLife.Model; +using NewLife.Reflection; +using NewLife.Threading; +using NewLife.Web; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; +using XCode.Membership; +using XCode.Shards; + +namespace XCode.Membership666; + +public partial class MemberLog : Entity +{ + #region 对象操作 + static MemberLog() + { + // 累加字段,生成 Update xx Set Count=Count+1234 Where xxx + //var df = Meta.Factory.AdditionalFields; + //df.Add(nameof(LinkID)); + + // 过滤器 UserModule、TimeModule、IPModule + Meta.Modules.Add(new UserModule { AllowEmpty = false }); + Meta.Modules.Add(); + Meta.Modules.Add(new IPModule { AllowEmpty = false }); + Meta.Modules.Add(); + } + + /// 验证并修补数据,返回验证结果,或者通过抛出异常的方式提示验证失败。 + /// 添删改方法 + public override Boolean Valid(DataMethod method) + { + //if (method == DataMethod.Delete) return true; + // 如果没有脏数据,则不需要进行任何处理 + if (!HasDirty) return true; + + // 建议先调用基类方法,基类方法会做一些统一处理 + if (!base.Valid(method)) return false; + + // 在新插入数据或者修改了指定字段时进行修正 + + // 保留2位小数 + //Ex3 = Math.Round(Ex3, 2); + + // 处理当前已登录用户信息,可以由UserModule过滤器代劳 + /*var user = ManageProvider.User; + if (user != null) + { + if (method == DataMethod.Insert && !Dirtys[nameof(CreateUserID)]) CreateUserID = user.ID; + }*/ + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateTime)]) CreateTime = DateTime.Now; + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateIP)]) CreateIP = ManageProvider.UserHost; + + return true; + } + + ///// 首次连接数据库时初始化数据,仅用于实体类重载,用户不应该调用该方法 + //[EditorBrowsable(EditorBrowsableState.Never)] + //protected override void InitData() + //{ + // // InitData一般用于当数据表没有数据时添加一些默认数据,该实体类的任何第一次数据库操作都会触发该方法,默认异步调用 + // if (Meta.Session.Count > 0) return; + + // if (XTrace.Debug) XTrace.WriteLine("开始初始化MemberLog[成员日志]数据……"); + + // var entity = new MemberLog(); + // entity.Ds = "abc"; + // entity.Category = "abc"; + // entity.Action = "abc"; + // entity.LinkID = 0; + // entity.Success = true; + // entity.UserName = "abc"; + // entity.Ex1 = 0; + // entity.Ex2 = 0; + // entity.Ex3 = 0.0; + // entity.Ex4 = "abc"; + // entity.Ex5 = "abc"; + // entity.Ex6 = "abc"; + // entity.Insert(); + + // if (XTrace.Debug) XTrace.WriteLine("完成初始化MemberLog[成员日志]数据!"); + //} + + ///// 已重载。基类先调用Valid(true)验证数据,然后在事务保护内调用OnInsert + ///// + //public override Int32 Insert() + //{ + // return base.Insert(); + //} + + ///// 已重载。在事务保护范围内处理业务,位于Valid之后 + ///// + //protected override Int32 OnDelete() + //{ + // return base.OnDelete(); + //} + #endregion + + #region 扩展属性 + #endregion + + #region 高级查询 + /// 高级查询 + /// 类别 + /// 操作 + /// 链接 + /// 创建用户 + /// 时间开始 + /// 时间结束 + /// 关键字 + /// 分页参数信息。可携带统计和数据权限扩展查询等信息 + /// 实体列表 + public static IList Search(String category, String action, Int32 linkId, Int32 createUserId, DateTime start, DateTime end, String key, PageParameter page) + { + var exp = new WhereExpression(); + + if (!category.IsNullOrEmpty()) exp &= _.Category == category; + if (!action.IsNullOrEmpty()) exp &= _.Action == action; + if (linkId >= 0) exp &= _.LinkID == linkId; + if (createUserId >= 0) exp &= _.CreateUserID == createUserId; + exp &= _.CreateTime.Between(start, end); + if (!key.IsNullOrEmpty()) exp &= _.Ds.Contains(key) | _.Category.Contains(key) | _.Action.Contains(key) | _.UserName.Contains(key) | _.Ex4.Contains(key) | _.Ex5.Contains(key) | _.Ex6.Contains(key) | _.TraceId.Contains(key) | _.CreateUser.Contains(key) | _.CreateIP.Contains(key) | _.Remark.Contains(key); + + return FindAll(exp, page); + } + + // Select Count(ID) as ID,Action From MemberLog Where CreateTime>'2020-01-24 00:00:00' Group By Action Order By ID Desc limit 20 + static readonly FieldCache _ActionCache = new FieldCache(nameof(Action)) + { + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + }; + + /// 获取操作列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + /// + public static IDictionary GetActionList() => _ActionCache.FindAllName(); + + // Select Count(ID) as ID,Category From MemberLog Where CreateTime>'2020-01-24 00:00:00' Group By Category Order By ID Desc limit 20 + static readonly FieldCache _CategoryCache = new FieldCache(nameof(Category)) + { + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + }; + + /// 获取类别列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + /// + public static IDictionary GetCategoryList() => _CategoryCache.FindAllName(); + #endregion + + #region 业务操作 + public IMemberLog ToModel() + { + var model = new MemberLog(); + model.Copy(this); + + return model; + } + + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/成员日志.cs b/XUnitTest.XCode/Code/Entity/成员日志.cs new file mode 100644 index 000000000..00978ce0b --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/成员日志.cs @@ -0,0 +1,473 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; + +namespace XCode.Membership666; + +/// 成员日志 +[Serializable] +[DataObject] +[Description("成员日志")] +[BindIndex("IX_MemberLog_Action_Category_ID", false, "Action,Category,ID")] +[BindIndex("IX_MemberLog_Category_LinkID_ID", false, "Category,LinkID,ID")] +[BindIndex("IX_MemberLog_CreateUserID_ID", false, "CreateUserID,ID")] +[BindTable("MemberLog", Description = "成员日志", ConnName = "Log", DbType = DatabaseType.None)] +public partial class MemberLog : IMemberLog, IEntity +{ + #region 属性 + private Int64 _ID; + /// 编号 + [DisplayName("编号")] + [Description("编号")] + [DataObjectField(true, true, false, 0)] + [BindColumn("ID", "编号", "")] + public Int64 ID { get => _ID; set { if (OnPropertyChanging("ID", value)) { _ID = value; OnPropertyChanged("ID"); } } } + + private String? _Ds; + /// 数据分区 + [DisplayName("数据分区")] + [Description("数据分区")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ds", "数据分区", "", DataScale = "time")] + public String? Ds { get => _Ds; set { if (OnPropertyChanging("Ds", value)) { _Ds = value; OnPropertyChanged("Ds"); } } } + + private String? _Category; + /// 类别 + [DisplayName("类别")] + [Description("类别")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Category", "类别", "")] + public String? Category { get => _Category; set { if (OnPropertyChanging("Category", value)) { _Category = value; OnPropertyChanged("Category"); } } } + + private String? _Action; + /// 操作 + [DisplayName("操作")] + [Description("操作")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Action", "操作", "")] + public String? Action { get => _Action; set { if (OnPropertyChanging("Action", value)) { _Action = value; OnPropertyChanged("Action"); } } } + + private Int32 _LinkID; + /// 链接 + [DisplayName("链接")] + [Description("链接")] + [DataObjectField(false, false, false, 0)] + [BindColumn("LinkID", "链接", "")] + public Int32 LinkID { get => _LinkID; set { if (OnPropertyChanging("LinkID", value)) { _LinkID = value; OnPropertyChanged("LinkID"); } } } + + private Boolean _Success; + /// 成功 + [DisplayName("成功")] + [Description("成功")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Success", "成功", "")] + public Boolean Success { get => _Success; set { if (OnPropertyChanging("Success", value)) { _Success = value; OnPropertyChanged("Success"); } } } + + private String? _UserName; + /// 用户名 + [DisplayName("用户名")] + [Description("用户名")] + [DataObjectField(false, false, true, 50)] + [BindColumn("UserName", "用户名", "")] + public String? UserName { get => _UserName; set { if (OnPropertyChanging("UserName", value)) { _UserName = value; OnPropertyChanged("UserName"); } } } + + private Int32 _Ex1; + /// 扩展1 + [Category("扩展")] + [DisplayName("扩展1")] + [Description("扩展1")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex1", "扩展1", "")] + public Int32 Ex1 { get => _Ex1; set { if (OnPropertyChanging("Ex1", value)) { _Ex1 = value; OnPropertyChanged("Ex1"); } } } + + private Int32 _Ex2; + /// 扩展2 + [Category("扩展")] + [DisplayName("扩展2")] + [Description("扩展2")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex2", "扩展2", "")] + public Int32 Ex2 { get => _Ex2; set { if (OnPropertyChanging("Ex2", value)) { _Ex2 = value; OnPropertyChanged("Ex2"); } } } + + private Double _Ex3; + /// 扩展3 + [Category("扩展")] + [DisplayName("扩展3")] + [Description("扩展3")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex3", "扩展3", "")] + public Double Ex3 { get => _Ex3; set { if (OnPropertyChanging("Ex3", value)) { _Ex3 = value; OnPropertyChanged("Ex3"); } } } + + private String? _Ex4; + /// 扩展4 + [Category("扩展")] + [DisplayName("扩展4")] + [Description("扩展4")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex4", "扩展4", "")] + public String? Ex4 { get => _Ex4; set { if (OnPropertyChanging("Ex4", value)) { _Ex4 = value; OnPropertyChanged("Ex4"); } } } + + private String? _Ex5; + /// 扩展5 + [Category("扩展")] + [DisplayName("扩展5")] + [Description("扩展5")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex5", "扩展5", "")] + public String? Ex5 { get => _Ex5; set { if (OnPropertyChanging("Ex5", value)) { _Ex5 = value; OnPropertyChanged("Ex5"); } } } + + private String? _Ex6; + /// 扩展6 + [Category("扩展")] + [DisplayName("扩展6")] + [Description("扩展6")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex6", "扩展6", "")] + public String? Ex6 { get => _Ex6; set { if (OnPropertyChanging("Ex6", value)) { _Ex6 = value; OnPropertyChanged("Ex6"); } } } + + private String? _TraceId; + /// 性能追踪。用于APM性能追踪定位,还原该事件的调用链 + [DisplayName("性能追踪")] + [Description("性能追踪。用于APM性能追踪定位,还原该事件的调用链")] + [DataObjectField(false, false, true, 50)] + [BindColumn("TraceId", "性能追踪。用于APM性能追踪定位,还原该事件的调用链", "")] + public String? TraceId { get => _TraceId; set { if (OnPropertyChanging("TraceId", value)) { _TraceId = value; OnPropertyChanged("TraceId"); } } } + + private String? _CreateUser; + /// 创建者 + [Category("扩展")] + [DisplayName("创建者")] + [Description("创建者")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateUser", "创建者", "")] + public String? CreateUser { get => _CreateUser; set { if (OnPropertyChanging("CreateUser", value)) { _CreateUser = value; OnPropertyChanged("CreateUser"); } } } + + private Int32 _CreateUserID; + /// 创建用户 + [Category("扩展")] + [DisplayName("创建用户")] + [Description("创建用户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateUserID", "创建用户", "")] + public Int32 CreateUserID { get => _CreateUserID; set { if (OnPropertyChanging("CreateUserID", value)) { _CreateUserID = value; OnPropertyChanged("CreateUserID"); } } } + + private String? _CreateIP; + /// 创建地址 + [Category("扩展")] + [DisplayName("创建地址")] + [Description("创建地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateIP", "创建地址", "")] + public String? CreateIP { get => _CreateIP; set { if (OnPropertyChanging("CreateIP", value)) { _CreateIP = value; OnPropertyChanged("CreateIP"); } } } + + private DateTime _CreateTime; + /// 时间 + [DisplayName("时间")] + [Description("时间")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateTime", "时间", "")] + public DateTime CreateTime { get => _CreateTime; set { if (OnPropertyChanging("CreateTime", value)) { _CreateTime = value; OnPropertyChanged("CreateTime"); } } } + + private String? _Remark; + /// 详细信息 + [DisplayName("详细信息")] + [Description("详细信息")] + [DataObjectField(false, false, true, 2000)] + [BindColumn("Remark", "详细信息", "")] + public String? Remark { get => _Remark; set { if (OnPropertyChanging("Remark", value)) { _Remark = value; OnPropertyChanged("Remark"); } } } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IMemberLog model) + { + ID = model.ID; + Ds = model.Ds; + Category = model.Category; + Action = model.Action; + LinkID = model.LinkID; + Success = model.Success; + UserName = model.UserName; + Ex1 = model.Ex1; + Ex2 = model.Ex2; + Ex3 = model.Ex3; + Ex4 = model.Ex4; + Ex5 = model.Ex5; + Ex6 = model.Ex6; + TraceId = model.TraceId; + CreateUser = model.CreateUser; + CreateUserID = model.CreateUserID; + CreateIP = model.CreateIP; + CreateTime = model.CreateTime; + Remark = model.Remark; + } + #endregion + + #region 获取/设置 字段值 + /// 获取/设置 字段值 + /// 字段名 + /// + public override Object? this[String name] + { + get => name switch + { + "ID" => _ID, + "Ds" => _Ds, + "Category" => _Category, + "Action" => _Action, + "LinkID" => _LinkID, + "Success" => _Success, + "UserName" => _UserName, + "Ex1" => _Ex1, + "Ex2" => _Ex2, + "Ex3" => _Ex3, + "Ex4" => _Ex4, + "Ex5" => _Ex5, + "Ex6" => _Ex6, + "TraceId" => _TraceId, + "CreateUser" => _CreateUser, + "CreateUserID" => _CreateUserID, + "CreateIP" => _CreateIP, + "CreateTime" => _CreateTime, + "Remark" => _Remark, + _ => base[name] + }; + set + { + switch (name) + { + case "ID": _ID = value.ToLong(); break; + case "Ds": _Ds = Convert.ToString(value); break; + case "Category": _Category = Convert.ToString(value); break; + case "Action": _Action = Convert.ToString(value); break; + case "LinkID": _LinkID = value.ToInt(); break; + case "Success": _Success = value.ToBoolean(); break; + case "UserName": _UserName = Convert.ToString(value); break; + case "Ex1": _Ex1 = value.ToInt(); break; + case "Ex2": _Ex2 = value.ToInt(); break; + case "Ex3": _Ex3 = value.ToDouble(); break; + case "Ex4": _Ex4 = Convert.ToString(value); break; + case "Ex5": _Ex5 = Convert.ToString(value); break; + case "Ex6": _Ex6 = Convert.ToString(value); break; + case "TraceId": _TraceId = Convert.ToString(value); break; + case "CreateUser": _CreateUser = Convert.ToString(value); break; + case "CreateUserID": _CreateUserID = value.ToInt(); break; + case "CreateIP": _CreateIP = Convert.ToString(value); break; + case "CreateTime": _CreateTime = value.ToDateTime(); break; + case "Remark": _Remark = Convert.ToString(value); break; + default: base[name] = value; break; + } + } + } + #endregion + + #region 关联映射 + /// 创建用户 + [XmlIgnore, IgnoreDataMember, ScriptIgnore] + public User? MyCreateUser => Extends.Get(nameof(MyCreateUser), k => User.FindByID(CreateUserID)); + + /// 创建用户 + [Map(nameof(CreateUserID), typeof(User), "ID")] + [Category("扩展")] + public String? CreateUserName => MyCreateUser?.ToString(); + + #endregion + + #region 扩展查询 + /// 根据编号查找 + /// 编号 + /// 实体对象 + public static MemberLog FindByID(Int64 id) + { + if (id < 0) return null; + + return Find(_.ID == id); + } + + /// 根据操作、类别查找 + /// 操作 + /// 类别 + /// 实体列表 + public static IList FindAllByActionAndCategory(String action, String category) + { + if (action.IsNullOrEmpty()) return []; + if (category.IsNullOrEmpty()) return []; + + return FindAll(_.Action == action & _.Category == category); + } + + /// 根据类别、链接查找 + /// 类别 + /// 链接 + /// 实体列表 + public static IList FindAllByCategoryAndLinkID(String category, Int32 linkId) + { + if (category.IsNullOrEmpty()) return []; + if (linkId < 0) return []; + + return FindAll(_.Category == category & _.LinkID == linkId); + } + + /// 根据创建用户查找 + /// 创建用户 + /// 实体列表 + public static IList FindAllByCreateUserID(Int32 createUserId) + { + if (createUserId < 0) return []; + + return FindAll(_.CreateUserID == createUserId); + } + #endregion + + #region 数据清理 + /// 清理指定时间段内的数据 + /// 开始时间。未指定时清理小于指定时间的所有数据 + /// 结束时间 + /// 清理行数 + public static Int32 DeleteWith(DateTime start, DateTime end) + { + if (start == end) return Delete(_.Ds == start); + + var where = new WhereExpression(); + if (start.Year > 2000) where &= _.Ds >= start; + if (end.Year > 2000) where &= _.Ds < end; + return Delete(where); + } + #endregion + + #region 字段名 + /// 取得成员日志字段信息的快捷方式 + public partial class _ + { + /// 编号 + public static readonly Field ID = FindByName("ID"); + + /// 数据分区 + public static readonly Field Ds = FindByName("Ds"); + + /// 类别 + public static readonly Field Category = FindByName("Category"); + + /// 操作 + public static readonly Field Action = FindByName("Action"); + + /// 链接 + public static readonly Field LinkID = FindByName("LinkID"); + + /// 成功 + public static readonly Field Success = FindByName("Success"); + + /// 用户名 + public static readonly Field UserName = FindByName("UserName"); + + /// 扩展1 + public static readonly Field Ex1 = FindByName("Ex1"); + + /// 扩展2 + public static readonly Field Ex2 = FindByName("Ex2"); + + /// 扩展3 + public static readonly Field Ex3 = FindByName("Ex3"); + + /// 扩展4 + public static readonly Field Ex4 = FindByName("Ex4"); + + /// 扩展5 + public static readonly Field Ex5 = FindByName("Ex5"); + + /// 扩展6 + public static readonly Field Ex6 = FindByName("Ex6"); + + /// 性能追踪。用于APM性能追踪定位,还原该事件的调用链 + public static readonly Field TraceId = FindByName("TraceId"); + + /// 创建者 + public static readonly Field CreateUser = FindByName("CreateUser"); + + /// 创建用户 + public static readonly Field CreateUserID = FindByName("CreateUserID"); + + /// 创建地址 + public static readonly Field CreateIP = FindByName("CreateIP"); + + /// 时间 + public static readonly Field CreateTime = FindByName("CreateTime"); + + /// 详细信息 + public static readonly Field Remark = FindByName("Remark"); + + static Field FindByName(String name) => Meta.Table.FindByName(name); + } + + /// 取得成员日志字段名称的快捷方式 + public partial class __ + { + /// 编号 + public const String ID = "ID"; + + /// 数据分区 + public const String Ds = "Ds"; + + /// 类别 + public const String Category = "Category"; + + /// 操作 + public const String Action = "Action"; + + /// 链接 + public const String LinkID = "LinkID"; + + /// 成功 + public const String Success = "Success"; + + /// 用户名 + public const String UserName = "UserName"; + + /// 扩展1 + public const String Ex1 = "Ex1"; + + /// 扩展2 + public const String Ex2 = "Ex2"; + + /// 扩展3 + public const String Ex3 = "Ex3"; + + /// 扩展4 + public const String Ex4 = "Ex4"; + + /// 扩展5 + public const String Ex5 = "Ex5"; + + /// 扩展6 + public const String Ex6 = "Ex6"; + + /// 性能追踪。用于APM性能追踪定位,还原该事件的调用链 + public const String TraceId = "TraceId"; + + /// 创建者 + public const String CreateUser = "CreateUser"; + + /// 创建用户 + public const String CreateUserID = "CreateUserID"; + + /// 创建地址 + public const String CreateIP = "CreateIP"; + + /// 时间 + public const String CreateTime = "CreateTime"; + + /// 详细信息 + public const String Remark = "Remark"; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/日志.Biz.cs b/XUnitTest.XCode/Code/Entity/日志.Biz.cs index 15abb3f2d..cedc1f363 100644 --- a/XUnitTest.XCode/Code/Entity/日志.Biz.cs +++ b/XUnitTest.XCode/Code/Entity/日志.Biz.cs @@ -24,7 +24,7 @@ using XCode.DataAccessLayer; using XCode.Membership; using XCode.Shards; -namespace XCode.Membership; +namespace XCode.Membership666; public partial class Log : Entity { diff --git a/XUnitTest.XCode/Code/Entity/日志.cs b/XUnitTest.XCode/Code/Entity/日志.cs index d55a18d1c..193b51511 100644 --- a/XUnitTest.XCode/Code/Entity/日志.cs +++ b/XUnitTest.XCode/Code/Entity/日志.cs @@ -11,7 +11,7 @@ using XCode.Cache; using XCode.Configuration; using XCode.DataAccessLayer; -namespace XCode.Membership; +namespace XCode.Membership666; /// 日志 [Serializable] @@ -25,11 +25,11 @@ public partial class Log : ILog, IEntity { #region 属性 private Int64 _ID; - /// 编号 + /// 编号。按天分表 [DisplayName("编号")] - [Description("编号")] + [Description("编号。按天分表")] [DataObjectField(true, false, false, 0)] - [BindColumn("ID", "编号", "", DataScale = "time")] + [BindColumn("ID", "编号。按天分表", "", DataScale = "timeShard:yyMMdd")] public Int64 ID { get => _ID; set { if (OnPropertyChanging("ID", value)) { _ID = value; OnPropertyChanged("ID"); } } } private String? _Category; @@ -318,11 +318,22 @@ public partial class Log : ILog, IEntity } #endregion + #region 数据清理 + /// 清理指定时间段内的数据 + /// 开始时间。未指定时清理小于指定时间的所有数据 + /// 结束时间 + /// 清理行数 + public static Int32 DeleteWith(DateTime start, DateTime end) + { + return Delete(_.ID.Between(start, end, Meta.Factory.Snow)); + } + #endregion + #region 字段名 /// 取得日志字段信息的快捷方式 public partial class _ { - /// 编号 + /// 编号。按天分表 public static readonly Field ID = FindByName("ID"); /// 类别 @@ -382,7 +393,7 @@ public partial class Log : ILog, IEntity /// 取得日志字段名称的快捷方式 public partial class __ { - /// 编号 + /// 编号。按天分表 public const String ID = "ID"; /// 类别 diff --git a/XUnitTest.XCode/Code/Entity/用户.Biz.cs b/XUnitTest.XCode/Code/Entity/用户.Biz.cs index d09b439f8..443d320b1 100644 --- a/XUnitTest.XCode/Code/Entity/用户.Biz.cs +++ b/XUnitTest.XCode/Code/Entity/用户.Biz.cs @@ -24,7 +24,7 @@ using XCode.DataAccessLayer; using XCode.Membership; using XCode.Shards; -namespace XCode.Membership; +namespace XCode.Membership666; public partial class User : Entity { diff --git a/XUnitTest.XCode/Code/Entity/用户.Biz2.cs b/XUnitTest.XCode/Code/Entity/用户.Biz2.cs index 5655b4311..e0fc4ff06 100644 --- a/XUnitTest.XCode/Code/Entity/用户.Biz2.cs +++ b/XUnitTest.XCode/Code/Entity/用户.Biz2.cs @@ -24,7 +24,7 @@ using XCode.DataAccessLayer; using XCode.Membership; using XCode.Shards; -namespace XCode.Membership; +namespace XCode.Membership666; public partial class User : Entity { diff --git a/XUnitTest.XCode/Code/Entity/用户.cs b/XUnitTest.XCode/Code/Entity/用户.cs index 97228b8d5..1fb155a3f 100644 --- a/XUnitTest.XCode/Code/Entity/用户.cs +++ b/XUnitTest.XCode/Code/Entity/用户.cs @@ -11,7 +11,7 @@ using XCode.Cache; using XCode.Configuration; using XCode.DataAccessLayer; -namespace XCode.Membership; +namespace XCode.Membership666; /// 用户。用户帐号信息 [Serializable] diff --git a/XUnitTest.XCode/Code/Entity/用户日志.Biz.cs b/XUnitTest.XCode/Code/Entity/用户日志.Biz.cs new file mode 100644 index 000000000..432bb0af5 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/用户日志.Biz.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using NewLife.Log; +using NewLife.Model; +using NewLife.Reflection; +using NewLife.Threading; +using NewLife.Web; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; +using XCode.Membership; +using XCode.Shards; + +namespace XCode.Membership666; + +public partial class UserLog : Entity +{ + #region 对象操作 + static UserLog() + { + // 累加字段,生成 Update xx Set Count=Count+1234 Where xxx + //var df = Meta.Factory.AdditionalFields; + //df.Add(nameof(LinkID)); + + // 过滤器 UserModule、TimeModule、IPModule + Meta.Modules.Add(new UserModule { AllowEmpty = false }); + Meta.Modules.Add(); + Meta.Modules.Add(new IPModule { AllowEmpty = false }); + Meta.Modules.Add(); + } + + /// 验证并修补数据,返回验证结果,或者通过抛出异常的方式提示验证失败。 + /// 添删改方法 + public override Boolean Valid(DataMethod method) + { + //if (method == DataMethod.Delete) return true; + // 如果没有脏数据,则不需要进行任何处理 + if (!HasDirty) return true; + + // 建议先调用基类方法,基类方法会做一些统一处理 + if (!base.Valid(method)) return false; + + // 在新插入数据或者修改了指定字段时进行修正 + + // 保留2位小数 + //Ex3 = Math.Round(Ex3, 2); + + // 处理当前已登录用户信息,可以由UserModule过滤器代劳 + /*var user = ManageProvider.User; + if (user != null) + { + if (method == DataMethod.Insert && !Dirtys[nameof(CreateUserID)]) CreateUserID = user.ID; + }*/ + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateTime)]) CreateTime = DateTime.Now; + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateIP)]) CreateIP = ManageProvider.UserHost; + + return true; + } + + ///// 首次连接数据库时初始化数据,仅用于实体类重载,用户不应该调用该方法 + //[EditorBrowsable(EditorBrowsableState.Never)] + //protected override void InitData() + //{ + // // InitData一般用于当数据表没有数据时添加一些默认数据,该实体类的任何第一次数据库操作都会触发该方法,默认异步调用 + // if (Meta.Session.Count > 0) return; + + // if (XTrace.Debug) XTrace.WriteLine("开始初始化UserLog[用户日志]数据……"); + + // var entity = new UserLog(); + // entity.DataTime = DateTime.Now; + // entity.Category = "abc"; + // entity.Action = "abc"; + // entity.LinkID = 0; + // entity.Success = true; + // entity.UserName = "abc"; + // entity.Ex1 = 0; + // entity.Ex2 = 0; + // entity.Ex3 = 0.0; + // entity.Ex4 = "abc"; + // entity.Ex5 = "abc"; + // entity.Ex6 = "abc"; + // entity.Insert(); + + // if (XTrace.Debug) XTrace.WriteLine("完成初始化UserLog[用户日志]数据!"); + //} + + ///// 已重载。基类先调用Valid(true)验证数据,然后在事务保护内调用OnInsert + ///// + //public override Int32 Insert() + //{ + // return base.Insert(); + //} + + ///// 已重载。在事务保护范围内处理业务,位于Valid之后 + ///// + //protected override Int32 OnDelete() + //{ + // return base.OnDelete(); + //} + #endregion + + #region 扩展属性 + #endregion + + #region 高级查询 + /// 高级查询 + /// 类别 + /// 操作 + /// 链接 + /// 创建用户 + /// 时间开始 + /// 时间结束 + /// 关键字 + /// 分页参数信息。可携带统计和数据权限扩展查询等信息 + /// 实体列表 + public static IList Search(String category, String action, Int32 linkId, Int32 createUserId, DateTime start, DateTime end, String key, PageParameter page) + { + var exp = new WhereExpression(); + + if (!category.IsNullOrEmpty()) exp &= _.Category == category; + if (!action.IsNullOrEmpty()) exp &= _.Action == action; + if (linkId >= 0) exp &= _.LinkID == linkId; + if (createUserId >= 0) exp &= _.CreateUserID == createUserId; + exp &= _.CreateTime.Between(start, end); + if (!key.IsNullOrEmpty()) exp &= _.Category.Contains(key) | _.Action.Contains(key) | _.UserName.Contains(key) | _.Ex4.Contains(key) | _.Ex5.Contains(key) | _.Ex6.Contains(key) | _.TraceId.Contains(key) | _.CreateUser.Contains(key) | _.CreateIP.Contains(key) | _.Remark.Contains(key); + + return FindAll(exp, page); + } + + // Select Count(ID) as ID,Action From UserLog Where CreateTime>'2020-01-24 00:00:00' Group By Action Order By ID Desc limit 20 + static readonly FieldCache _ActionCache = new FieldCache(nameof(Action)) + { + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + }; + + /// 获取操作列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + /// + public static IDictionary GetActionList() => _ActionCache.FindAllName(); + + // Select Count(ID) as ID,Category From UserLog Where CreateTime>'2020-01-24 00:00:00' Group By Category Order By ID Desc limit 20 + static readonly FieldCache _CategoryCache = new FieldCache(nameof(Category)) + { + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + }; + + /// 获取类别列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + /// + public static IDictionary GetCategoryList() => _CategoryCache.FindAllName(); + #endregion + + #region 业务操作 + public IUserLog ToModel() + { + var model = new UserLog(); + model.Copy(this); + + return model; + } + + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/用户日志.cs b/XUnitTest.XCode/Code/Entity/用户日志.cs new file mode 100644 index 000000000..094464db4 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/用户日志.cs @@ -0,0 +1,470 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; + +namespace XCode.Membership666; + +/// 用户日志 +[Serializable] +[DataObject] +[Description("用户日志")] +[BindIndex("IX_UserLog_Action_Category_ID", false, "Action,Category,ID")] +[BindIndex("IX_UserLog_Category_LinkID_ID", false, "Category,LinkID,ID")] +[BindIndex("IX_UserLog_CreateUserID_ID", false, "CreateUserID,ID")] +[BindTable("UserLog", Description = "用户日志", ConnName = "Log", DbType = DatabaseType.None)] +public partial class UserLog : IUserLog, IEntity +{ + #region 属性 + private Int64 _ID; + /// 编号 + [DisplayName("编号")] + [Description("编号")] + [DataObjectField(true, true, false, 0)] + [BindColumn("ID", "编号", "")] + public Int64 ID { get => _ID; set { if (OnPropertyChanging("ID", value)) { _ID = value; OnPropertyChanged("ID"); } } } + + private DateTime _DataTime; + /// 数据时间。按月分表 + [DisplayName("数据时间")] + [Description("数据时间。按月分表")] + [DataObjectField(false, false, true, 0)] + [BindColumn("DataTime", "数据时间。按月分表", "", DataScale = "timeShard:yyMM")] + public DateTime DataTime { get => _DataTime; set { if (OnPropertyChanging("DataTime", value)) { _DataTime = value; OnPropertyChanged("DataTime"); } } } + + private String? _Category; + /// 类别 + [DisplayName("类别")] + [Description("类别")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Category", "类别", "")] + public String? Category { get => _Category; set { if (OnPropertyChanging("Category", value)) { _Category = value; OnPropertyChanged("Category"); } } } + + private String? _Action; + /// 操作 + [DisplayName("操作")] + [Description("操作")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Action", "操作", "")] + public String? Action { get => _Action; set { if (OnPropertyChanging("Action", value)) { _Action = value; OnPropertyChanged("Action"); } } } + + private Int32 _LinkID; + /// 链接 + [DisplayName("链接")] + [Description("链接")] + [DataObjectField(false, false, false, 0)] + [BindColumn("LinkID", "链接", "")] + public Int32 LinkID { get => _LinkID; set { if (OnPropertyChanging("LinkID", value)) { _LinkID = value; OnPropertyChanged("LinkID"); } } } + + private Boolean _Success; + /// 成功 + [DisplayName("成功")] + [Description("成功")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Success", "成功", "")] + public Boolean Success { get => _Success; set { if (OnPropertyChanging("Success", value)) { _Success = value; OnPropertyChanged("Success"); } } } + + private String? _UserName; + /// 用户名 + [DisplayName("用户名")] + [Description("用户名")] + [DataObjectField(false, false, true, 50)] + [BindColumn("UserName", "用户名", "")] + public String? UserName { get => _UserName; set { if (OnPropertyChanging("UserName", value)) { _UserName = value; OnPropertyChanged("UserName"); } } } + + private Int32 _Ex1; + /// 扩展1 + [Category("扩展")] + [DisplayName("扩展1")] + [Description("扩展1")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex1", "扩展1", "")] + public Int32 Ex1 { get => _Ex1; set { if (OnPropertyChanging("Ex1", value)) { _Ex1 = value; OnPropertyChanged("Ex1"); } } } + + private Int32 _Ex2; + /// 扩展2 + [Category("扩展")] + [DisplayName("扩展2")] + [Description("扩展2")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex2", "扩展2", "")] + public Int32 Ex2 { get => _Ex2; set { if (OnPropertyChanging("Ex2", value)) { _Ex2 = value; OnPropertyChanged("Ex2"); } } } + + private Double _Ex3; + /// 扩展3 + [Category("扩展")] + [DisplayName("扩展3")] + [Description("扩展3")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex3", "扩展3", "")] + public Double Ex3 { get => _Ex3; set { if (OnPropertyChanging("Ex3", value)) { _Ex3 = value; OnPropertyChanged("Ex3"); } } } + + private String? _Ex4; + /// 扩展4 + [Category("扩展")] + [DisplayName("扩展4")] + [Description("扩展4")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex4", "扩展4", "")] + public String? Ex4 { get => _Ex4; set { if (OnPropertyChanging("Ex4", value)) { _Ex4 = value; OnPropertyChanged("Ex4"); } } } + + private String? _Ex5; + /// 扩展5 + [Category("扩展")] + [DisplayName("扩展5")] + [Description("扩展5")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex5", "扩展5", "")] + public String? Ex5 { get => _Ex5; set { if (OnPropertyChanging("Ex5", value)) { _Ex5 = value; OnPropertyChanged("Ex5"); } } } + + private String? _Ex6; + /// 扩展6 + [Category("扩展")] + [DisplayName("扩展6")] + [Description("扩展6")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex6", "扩展6", "")] + public String? Ex6 { get => _Ex6; set { if (OnPropertyChanging("Ex6", value)) { _Ex6 = value; OnPropertyChanged("Ex6"); } } } + + private String? _TraceId; + /// 性能追踪。用于APM性能追踪定位,还原该事件的调用链 + [DisplayName("性能追踪")] + [Description("性能追踪。用于APM性能追踪定位,还原该事件的调用链")] + [DataObjectField(false, false, true, 50)] + [BindColumn("TraceId", "性能追踪。用于APM性能追踪定位,还原该事件的调用链", "")] + public String? TraceId { get => _TraceId; set { if (OnPropertyChanging("TraceId", value)) { _TraceId = value; OnPropertyChanged("TraceId"); } } } + + private String? _CreateUser; + /// 创建者 + [Category("扩展")] + [DisplayName("创建者")] + [Description("创建者")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateUser", "创建者", "")] + public String? CreateUser { get => _CreateUser; set { if (OnPropertyChanging("CreateUser", value)) { _CreateUser = value; OnPropertyChanged("CreateUser"); } } } + + private Int32 _CreateUserID; + /// 创建用户 + [Category("扩展")] + [DisplayName("创建用户")] + [Description("创建用户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateUserID", "创建用户", "")] + public Int32 CreateUserID { get => _CreateUserID; set { if (OnPropertyChanging("CreateUserID", value)) { _CreateUserID = value; OnPropertyChanged("CreateUserID"); } } } + + private String? _CreateIP; + /// 创建地址 + [Category("扩展")] + [DisplayName("创建地址")] + [Description("创建地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateIP", "创建地址", "")] + public String? CreateIP { get => _CreateIP; set { if (OnPropertyChanging("CreateIP", value)) { _CreateIP = value; OnPropertyChanged("CreateIP"); } } } + + private DateTime _CreateTime; + /// 时间 + [DisplayName("时间")] + [Description("时间")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateTime", "时间", "")] + public DateTime CreateTime { get => _CreateTime; set { if (OnPropertyChanging("CreateTime", value)) { _CreateTime = value; OnPropertyChanged("CreateTime"); } } } + + private String? _Remark; + /// 详细信息 + [DisplayName("详细信息")] + [Description("详细信息")] + [DataObjectField(false, false, true, 2000)] + [BindColumn("Remark", "详细信息", "")] + public String? Remark { get => _Remark; set { if (OnPropertyChanging("Remark", value)) { _Remark = value; OnPropertyChanged("Remark"); } } } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IUserLog model) + { + ID = model.ID; + DataTime = model.DataTime; + Category = model.Category; + Action = model.Action; + LinkID = model.LinkID; + Success = model.Success; + UserName = model.UserName; + Ex1 = model.Ex1; + Ex2 = model.Ex2; + Ex3 = model.Ex3; + Ex4 = model.Ex4; + Ex5 = model.Ex5; + Ex6 = model.Ex6; + TraceId = model.TraceId; + CreateUser = model.CreateUser; + CreateUserID = model.CreateUserID; + CreateIP = model.CreateIP; + CreateTime = model.CreateTime; + Remark = model.Remark; + } + #endregion + + #region 获取/设置 字段值 + /// 获取/设置 字段值 + /// 字段名 + /// + public override Object? this[String name] + { + get => name switch + { + "ID" => _ID, + "DataTime" => _DataTime, + "Category" => _Category, + "Action" => _Action, + "LinkID" => _LinkID, + "Success" => _Success, + "UserName" => _UserName, + "Ex1" => _Ex1, + "Ex2" => _Ex2, + "Ex3" => _Ex3, + "Ex4" => _Ex4, + "Ex5" => _Ex5, + "Ex6" => _Ex6, + "TraceId" => _TraceId, + "CreateUser" => _CreateUser, + "CreateUserID" => _CreateUserID, + "CreateIP" => _CreateIP, + "CreateTime" => _CreateTime, + "Remark" => _Remark, + _ => base[name] + }; + set + { + switch (name) + { + case "ID": _ID = value.ToLong(); break; + case "DataTime": _DataTime = value.ToDateTime(); break; + case "Category": _Category = Convert.ToString(value); break; + case "Action": _Action = Convert.ToString(value); break; + case "LinkID": _LinkID = value.ToInt(); break; + case "Success": _Success = value.ToBoolean(); break; + case "UserName": _UserName = Convert.ToString(value); break; + case "Ex1": _Ex1 = value.ToInt(); break; + case "Ex2": _Ex2 = value.ToInt(); break; + case "Ex3": _Ex3 = value.ToDouble(); break; + case "Ex4": _Ex4 = Convert.ToString(value); break; + case "Ex5": _Ex5 = Convert.ToString(value); break; + case "Ex6": _Ex6 = Convert.ToString(value); break; + case "TraceId": _TraceId = Convert.ToString(value); break; + case "CreateUser": _CreateUser = Convert.ToString(value); break; + case "CreateUserID": _CreateUserID = value.ToInt(); break; + case "CreateIP": _CreateIP = Convert.ToString(value); break; + case "CreateTime": _CreateTime = value.ToDateTime(); break; + case "Remark": _Remark = Convert.ToString(value); break; + default: base[name] = value; break; + } + } + } + #endregion + + #region 关联映射 + /// 创建用户 + [XmlIgnore, IgnoreDataMember, ScriptIgnore] + public User? MyCreateUser => Extends.Get(nameof(MyCreateUser), k => User.FindByID(CreateUserID)); + + /// 创建用户 + [Map(nameof(CreateUserID), typeof(User), "ID")] + [Category("扩展")] + public String? CreateUserName => MyCreateUser?.ToString(); + + #endregion + + #region 扩展查询 + /// 根据编号查找 + /// 编号 + /// 实体对象 + public static UserLog FindByID(Int64 id) + { + if (id < 0) return null; + + return Find(_.ID == id); + } + + /// 根据操作、类别查找 + /// 操作 + /// 类别 + /// 实体列表 + public static IList FindAllByActionAndCategory(String action, String category) + { + if (action.IsNullOrEmpty()) return []; + if (category.IsNullOrEmpty()) return []; + + return FindAll(_.Action == action & _.Category == category); + } + + /// 根据类别、链接查找 + /// 类别 + /// 链接 + /// 实体列表 + public static IList FindAllByCategoryAndLinkID(String category, Int32 linkId) + { + if (category.IsNullOrEmpty()) return []; + if (linkId < 0) return []; + + return FindAll(_.Category == category & _.LinkID == linkId); + } + + /// 根据创建用户查找 + /// 创建用户 + /// 实体列表 + public static IList FindAllByCreateUserID(Int32 createUserId) + { + if (createUserId < 0) return []; + + return FindAll(_.CreateUserID == createUserId); + } + #endregion + + #region 数据清理 + /// 清理指定时间段内的数据 + /// 开始时间。未指定时清理小于指定时间的所有数据 + /// 结束时间 + /// 清理行数 + public static Int32 DeleteWith(DateTime start, DateTime end) + { + if (start == end) return Delete(_.DataTime == start); + + return Delete(_.DataTime.Between(start, end)); + } + #endregion + + #region 字段名 + /// 取得用户日志字段信息的快捷方式 + public partial class _ + { + /// 编号 + public static readonly Field ID = FindByName("ID"); + + /// 数据时间。按月分表 + public static readonly Field DataTime = FindByName("DataTime"); + + /// 类别 + public static readonly Field Category = FindByName("Category"); + + /// 操作 + public static readonly Field Action = FindByName("Action"); + + /// 链接 + public static readonly Field LinkID = FindByName("LinkID"); + + /// 成功 + public static readonly Field Success = FindByName("Success"); + + /// 用户名 + public static readonly Field UserName = FindByName("UserName"); + + /// 扩展1 + public static readonly Field Ex1 = FindByName("Ex1"); + + /// 扩展2 + public static readonly Field Ex2 = FindByName("Ex2"); + + /// 扩展3 + public static readonly Field Ex3 = FindByName("Ex3"); + + /// 扩展4 + public static readonly Field Ex4 = FindByName("Ex4"); + + /// 扩展5 + public static readonly Field Ex5 = FindByName("Ex5"); + + /// 扩展6 + public static readonly Field Ex6 = FindByName("Ex6"); + + /// 性能追踪。用于APM性能追踪定位,还原该事件的调用链 + public static readonly Field TraceId = FindByName("TraceId"); + + /// 创建者 + public static readonly Field CreateUser = FindByName("CreateUser"); + + /// 创建用户 + public static readonly Field CreateUserID = FindByName("CreateUserID"); + + /// 创建地址 + public static readonly Field CreateIP = FindByName("CreateIP"); + + /// 时间 + public static readonly Field CreateTime = FindByName("CreateTime"); + + /// 详细信息 + public static readonly Field Remark = FindByName("Remark"); + + static Field FindByName(String name) => Meta.Table.FindByName(name); + } + + /// 取得用户日志字段名称的快捷方式 + public partial class __ + { + /// 编号 + public const String ID = "ID"; + + /// 数据时间。按月分表 + public const String DataTime = "DataTime"; + + /// 类别 + public const String Category = "Category"; + + /// 操作 + public const String Action = "Action"; + + /// 链接 + public const String LinkID = "LinkID"; + + /// 成功 + public const String Success = "Success"; + + /// 用户名 + public const String UserName = "UserName"; + + /// 扩展1 + public const String Ex1 = "Ex1"; + + /// 扩展2 + public const String Ex2 = "Ex2"; + + /// 扩展3 + public const String Ex3 = "Ex3"; + + /// 扩展4 + public const String Ex4 = "Ex4"; + + /// 扩展5 + public const String Ex5 = "Ex5"; + + /// 扩展6 + public const String Ex6 = "Ex6"; + + /// 性能追踪。用于APM性能追踪定位,还原该事件的调用链 + public const String TraceId = "TraceId"; + + /// 创建者 + public const String CreateUser = "CreateUser"; + + /// 创建用户 + public const String CreateUserID = "CreateUserID"; + + /// 创建地址 + public const String CreateIP = "CreateIP"; + + /// 时间 + public const String CreateTime = "CreateTime"; + + /// 详细信息 + public const String Remark = "Remark"; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/租户.Biz.cs b/XUnitTest.XCode/Code/Entity/租户.Biz.cs new file mode 100644 index 000000000..049f2e944 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/租户.Biz.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using NewLife.Log; +using NewLife.Model; +using NewLife.Reflection; +using NewLife.Threading; +using NewLife.Web; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; +using XCode.Membership; +using XCode.Shards; + +namespace XCode.Membership666; + +public partial class Tenant : Entity +{ + #region 对象操作 + static Tenant() + { + // 累加字段,生成 Update xx Set Count=Count+1234 Where xxx + //var df = Meta.Factory.AdditionalFields; + //df.Add(nameof(ManagerId)); + + // 过滤器 UserModule、TimeModule、IPModule + Meta.Modules.Add(new UserModule { AllowEmpty = false }); + Meta.Modules.Add(); + Meta.Modules.Add(new IPModule { AllowEmpty = false }); + + // 实体缓存 + // var ec = Meta.Cache; + // ec.Expire = 60; + } + + /// 验证并修补数据,返回验证结果,或者通过抛出异常的方式提示验证失败。 + /// 添删改方法 + public override Boolean Valid(DataMethod method) + { + //if (method == DataMethod.Delete) return true; + // 如果没有脏数据,则不需要进行任何处理 + if (!HasDirty) return true; + + // 建议先调用基类方法,基类方法会做一些统一处理 + if (!base.Valid(method)) return false; + + // 在新插入数据或者修改了指定字段时进行修正 + + // 处理当前已登录用户信息,可以由UserModule过滤器代劳 + /*var user = ManageProvider.User; + if (user != null) + { + if (method == DataMethod.Insert && !Dirtys[nameof(CreateUserId)]) CreateUserId = user.ID; + if (!Dirtys[nameof(UpdateUserId)]) UpdateUserId = user.ID; + }*/ + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateTime)]) CreateTime = DateTime.Now; + //if (!Dirtys[nameof(UpdateTime)]) UpdateTime = DateTime.Now; + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateIP)]) CreateIP = ManageProvider.UserHost; + //if (!Dirtys[nameof(UpdateIP)]) UpdateIP = ManageProvider.UserHost; + + // 检查唯一索引 + // CheckExist(method == DataMethod.Insert, nameof(Code)); + + return true; + } + + ///// 首次连接数据库时初始化数据,仅用于实体类重载,用户不应该调用该方法 + //[EditorBrowsable(EditorBrowsableState.Never)] + //protected override void InitData() + //{ + // // InitData一般用于当数据表没有数据时添加一些默认数据,该实体类的任何第一次数据库操作都会触发该方法,默认异步调用 + // if (Meta.Session.Count > 0) return; + + // if (XTrace.Debug) XTrace.WriteLine("开始初始化Tenant[租户]数据……"); + + // var entity = new Tenant(); + // entity.Code = "abc"; + // entity.Name = "abc"; + // entity.Enable = true; + // entity.ManagerId = 0; + // entity.RoleIds = "abc"; + // entity.Logo = "abc"; + // entity.DatabaseName = "abc"; + // entity.TableName = "abc"; + // entity.Expired = DateTime.Now; + // entity.Insert(); + + // if (XTrace.Debug) XTrace.WriteLine("完成初始化Tenant[租户]数据!"); + //} + + ///// 已重载。基类先调用Valid(true)验证数据,然后在事务保护内调用OnInsert + ///// + //public override Int32 Insert() + //{ + // return base.Insert(); + //} + + ///// 已重载。在事务保护范围内处理业务,位于Valid之后 + ///// + //protected override Int32 OnDelete() + //{ + // return base.OnDelete(); + //} + #endregion + + #region 扩展属性 + #endregion + + #region 高级查询 + /// 高级查询 + /// 编码。唯一编码 + /// 更新时间开始 + /// 更新时间结束 + /// 关键字 + /// 分页参数信息。可携带统计和数据权限扩展查询等信息 + /// 实体列表 + public static IList Search(String code, DateTime start, DateTime end, String key, PageParameter page) + { + var exp = new WhereExpression(); + + if (!code.IsNullOrEmpty()) exp &= _.Code == code; + exp &= _.UpdateTime.Between(start, end); + if (!key.IsNullOrEmpty()) exp &= _.Code.Contains(key) | _.Name.Contains(key) | _.RoleIds.Contains(key) | _.Logo.Contains(key) | _.DatabaseName.Contains(key) | _.TableName.Contains(key) | _.CreateIP.Contains(key) | _.UpdateIP.Contains(key) | _.Remark.Contains(key); + + return FindAll(exp, page); + } + + // Select Count(Id) as Id,Category From Tenant Where CreateTime>'2020-01-24 00:00:00' Group By Category Order By Id Desc limit 20 + //static readonly FieldCache _CategoryCache = new FieldCache(nameof(Category)) + //{ + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + //}; + + ///// 获取类别列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + ///// + //public static IDictionary GetCategoryList() => _CategoryCache.FindAllName(); + #endregion + + #region 业务操作 + public ITenant ToModel() + { + var model = new Tenant(); + model.Copy(this); + + return model; + } + + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/租户.cs b/XUnitTest.XCode/Code/Entity/租户.cs new file mode 100644 index 000000000..89bd7b1d0 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/租户.cs @@ -0,0 +1,397 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; + +namespace XCode.Membership666; + +/// 租户。多租户SAAS平台,用于隔离业务数据 +[Serializable] +[DataObject] +[Description("租户。多租户SAAS平台,用于隔离业务数据")] +[BindIndex("IU_Tenant_Code", true, "Code")] +[BindTable("Tenant", Description = "租户。多租户SAAS平台,用于隔离业务数据", ConnName = "Membership", DbType = DatabaseType.None)] +public partial class Tenant : ITenant, IEntity +{ + #region 属性 + private Int32 _Id; + /// 编号 + [DisplayName("编号")] + [Description("编号")] + [DataObjectField(true, true, false, 0)] + [BindColumn("Id", "编号", "")] + public Int32 Id { get => _Id; set { if (OnPropertyChanging("Id", value)) { _Id = value; OnPropertyChanged("Id"); } } } + + private String? _Code; + /// 编码。唯一编码 + [DisplayName("编码")] + [Description("编码。唯一编码")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Code", "编码。唯一编码", "")] + public String? Code { get => _Code; set { if (OnPropertyChanging("Code", value)) { _Code = value; OnPropertyChanged("Code"); } } } + + private String? _Name; + /// 名称。显示名称 + [DisplayName("名称")] + [Description("名称。显示名称")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Name", "名称。显示名称", "", Master = true)] + public String? Name { get => _Name; set { if (OnPropertyChanging("Name", value)) { _Name = value; OnPropertyChanged("Name"); } } } + + private Boolean _Enable; + /// 启用 + [DisplayName("启用")] + [Description("启用")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Enable", "启用", "")] + public Boolean Enable { get => _Enable; set { if (OnPropertyChanging("Enable", value)) { _Enable = value; OnPropertyChanged("Enable"); } } } + + private Int32 _ManagerId; + /// 管理者 + [DisplayName("管理者")] + [Description("管理者")] + [DataObjectField(false, false, false, 0)] + [BindColumn("ManagerId", "管理者", "")] + public Int32 ManagerId { get => _ManagerId; set { if (OnPropertyChanging("ManagerId", value)) { _ManagerId = value; OnPropertyChanged("ManagerId"); } } } + + private String? _RoleIds; + /// 角色组。租户可选的角色集合,不同级别的租户所拥有的角色不一样,高级功能也会不同 + [DisplayName("角色组")] + [Description("角色组。租户可选的角色集合,不同级别的租户所拥有的角色不一样,高级功能也会不同")] + [DataObjectField(false, false, true, 200)] + [BindColumn("RoleIds", "角色组。租户可选的角色集合,不同级别的租户所拥有的角色不一样,高级功能也会不同", "")] + public String? RoleIds { get => _RoleIds; set { if (OnPropertyChanging("RoleIds", value)) { _RoleIds = value; OnPropertyChanged("RoleIds"); } } } + + private String? _Logo; + /// 图标。附件路径 + [DisplayName("图标")] + [Description("图标。附件路径")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Logo", "图标。附件路径", "", ItemType = "image")] + public String? Logo { get => _Logo; set { if (OnPropertyChanging("Logo", value)) { _Logo = value; OnPropertyChanged("Logo"); } } } + + private String? _DatabaseName; + /// 数据库。分库用的数据库名 + [DisplayName("数据库")] + [Description("数据库。分库用的数据库名")] + [DataObjectField(false, false, true, 50)] + [BindColumn("DatabaseName", "数据库。分库用的数据库名", "")] + public String? DatabaseName { get => _DatabaseName; set { if (OnPropertyChanging("DatabaseName", value)) { _DatabaseName = value; OnPropertyChanged("DatabaseName"); } } } + + private String? _TableName; + /// 数据表。分表用的数据表前缀 + [DisplayName("数据表")] + [Description("数据表。分表用的数据表前缀")] + [DataObjectField(false, false, true, 50)] + [BindColumn("TableName", "数据表。分表用的数据表前缀", "")] + public String? TableName { get => _TableName; set { if (OnPropertyChanging("TableName", value)) { _TableName = value; OnPropertyChanged("TableName"); } } } + + private DateTime _Expired; + /// 过期时间。达到该时间后,自动禁用租户,空表示永不过期 + [DisplayName("过期时间")] + [Description("过期时间。达到该时间后,自动禁用租户,空表示永不过期")] + [DataObjectField(false, false, true, 0)] + [BindColumn("Expired", "过期时间。达到该时间后,自动禁用租户,空表示永不过期", "")] + public DateTime Expired { get => _Expired; set { if (OnPropertyChanging("Expired", value)) { _Expired = value; OnPropertyChanged("Expired"); } } } + + private Int32 _CreateUserId; + /// 创建者 + [Category("扩展")] + [DisplayName("创建者")] + [Description("创建者")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateUserId", "创建者", "")] + public Int32 CreateUserId { get => _CreateUserId; set { if (OnPropertyChanging("CreateUserId", value)) { _CreateUserId = value; OnPropertyChanged("CreateUserId"); } } } + + private DateTime _CreateTime; + /// 创建时间 + [Category("扩展")] + [DisplayName("创建时间")] + [Description("创建时间")] + [DataObjectField(false, false, true, 0)] + [BindColumn("CreateTime", "创建时间", "")] + public DateTime CreateTime { get => _CreateTime; set { if (OnPropertyChanging("CreateTime", value)) { _CreateTime = value; OnPropertyChanged("CreateTime"); } } } + + private String? _CreateIP; + /// 创建地址 + [Category("扩展")] + [DisplayName("创建地址")] + [Description("创建地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateIP", "创建地址", "")] + public String? CreateIP { get => _CreateIP; set { if (OnPropertyChanging("CreateIP", value)) { _CreateIP = value; OnPropertyChanged("CreateIP"); } } } + + private Int32 _UpdateUserId; + /// 更新者 + [Category("扩展")] + [DisplayName("更新者")] + [Description("更新者")] + [DataObjectField(false, false, false, 0)] + [BindColumn("UpdateUserId", "更新者", "")] + public Int32 UpdateUserId { get => _UpdateUserId; set { if (OnPropertyChanging("UpdateUserId", value)) { _UpdateUserId = value; OnPropertyChanged("UpdateUserId"); } } } + + private DateTime _UpdateTime; + /// 更新时间 + [Category("扩展")] + [DisplayName("更新时间")] + [Description("更新时间")] + [DataObjectField(false, false, true, 0)] + [BindColumn("UpdateTime", "更新时间", "")] + public DateTime UpdateTime { get => _UpdateTime; set { if (OnPropertyChanging("UpdateTime", value)) { _UpdateTime = value; OnPropertyChanged("UpdateTime"); } } } + + private String? _UpdateIP; + /// 更新地址 + [Category("扩展")] + [DisplayName("更新地址")] + [Description("更新地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("UpdateIP", "更新地址", "")] + public String? UpdateIP { get => _UpdateIP; set { if (OnPropertyChanging("UpdateIP", value)) { _UpdateIP = value; OnPropertyChanged("UpdateIP"); } } } + + private String? _Remark; + /// 描述 + [Category("扩展")] + [DisplayName("描述")] + [Description("描述")] + [DataObjectField(false, false, true, 500)] + [BindColumn("Remark", "描述", "")] + public String? Remark { get => _Remark; set { if (OnPropertyChanging("Remark", value)) { _Remark = value; OnPropertyChanged("Remark"); } } } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(ITenant model) + { + Id = model.Id; + Code = model.Code; + Name = model.Name; + Enable = model.Enable; + ManagerId = model.ManagerId; + RoleIds = model.RoleIds; + Logo = model.Logo; + DatabaseName = model.DatabaseName; + TableName = model.TableName; + Expired = model.Expired; + Remark = model.Remark; + } + #endregion + + #region 获取/设置 字段值 + /// 获取/设置 字段值 + /// 字段名 + /// + public override Object? this[String name] + { + get => name switch + { + "Id" => _Id, + "Code" => _Code, + "Name" => _Name, + "Enable" => _Enable, + "ManagerId" => _ManagerId, + "RoleIds" => _RoleIds, + "Logo" => _Logo, + "DatabaseName" => _DatabaseName, + "TableName" => _TableName, + "Expired" => _Expired, + "CreateUserId" => _CreateUserId, + "CreateTime" => _CreateTime, + "CreateIP" => _CreateIP, + "UpdateUserId" => _UpdateUserId, + "UpdateTime" => _UpdateTime, + "UpdateIP" => _UpdateIP, + "Remark" => _Remark, + _ => base[name] + }; + set + { + switch (name) + { + case "Id": _Id = value.ToInt(); break; + case "Code": _Code = Convert.ToString(value); break; + case "Name": _Name = Convert.ToString(value); break; + case "Enable": _Enable = value.ToBoolean(); break; + case "ManagerId": _ManagerId = value.ToInt(); break; + case "RoleIds": _RoleIds = Convert.ToString(value); break; + case "Logo": _Logo = Convert.ToString(value); break; + case "DatabaseName": _DatabaseName = Convert.ToString(value); break; + case "TableName": _TableName = Convert.ToString(value); break; + case "Expired": _Expired = value.ToDateTime(); break; + case "CreateUserId": _CreateUserId = value.ToInt(); break; + case "CreateTime": _CreateTime = value.ToDateTime(); break; + case "CreateIP": _CreateIP = Convert.ToString(value); break; + case "UpdateUserId": _UpdateUserId = value.ToInt(); break; + case "UpdateTime": _UpdateTime = value.ToDateTime(); break; + case "UpdateIP": _UpdateIP = Convert.ToString(value); break; + case "Remark": _Remark = Convert.ToString(value); break; + default: base[name] = value; break; + } + } + } + #endregion + + #region 关联映射 + /// 管理者 + [XmlIgnore, IgnoreDataMember, ScriptIgnore] + public User? Manager => Extends.Get(nameof(Manager), k => User.FindByID(ManagerId)); + + /// 管理者 + [Map(nameof(ManagerId), typeof(User), "ID")] + public String? ManagerName => Manager?.ToString(); + + #endregion + + #region 扩展查询 + /// 根据编号查找 + /// 编号 + /// 实体对象 + public static Tenant FindById(Int32 id) + { + if (id < 0) return null; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.Id == id); + + // 单对象缓存 + return Meta.SingleCache[id]; + + //return Find(_.Id == id); + } + + /// 根据编码查找 + /// 编码 + /// 实体对象 + public static Tenant FindByCode(String code) + { + if (code.IsNullOrEmpty()) return null; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.Code.EqualIgnoreCase(code)); + + return Find(_.Code == code); + } + #endregion + + #region 字段名 + /// 取得租户字段信息的快捷方式 + public partial class _ + { + /// 编号 + public static readonly Field Id = FindByName("Id"); + + /// 编码。唯一编码 + public static readonly Field Code = FindByName("Code"); + + /// 名称。显示名称 + public static readonly Field Name = FindByName("Name"); + + /// 启用 + public static readonly Field Enable = FindByName("Enable"); + + /// 管理者 + public static readonly Field ManagerId = FindByName("ManagerId"); + + /// 角色组。租户可选的角色集合,不同级别的租户所拥有的角色不一样,高级功能也会不同 + public static readonly Field RoleIds = FindByName("RoleIds"); + + /// 图标。附件路径 + public static readonly Field Logo = FindByName("Logo"); + + /// 数据库。分库用的数据库名 + public static readonly Field DatabaseName = FindByName("DatabaseName"); + + /// 数据表。分表用的数据表前缀 + public static readonly Field TableName = FindByName("TableName"); + + /// 过期时间。达到该时间后,自动禁用租户,空表示永不过期 + public static readonly Field Expired = FindByName("Expired"); + + /// 创建者 + public static readonly Field CreateUserId = FindByName("CreateUserId"); + + /// 创建时间 + public static readonly Field CreateTime = FindByName("CreateTime"); + + /// 创建地址 + public static readonly Field CreateIP = FindByName("CreateIP"); + + /// 更新者 + public static readonly Field UpdateUserId = FindByName("UpdateUserId"); + + /// 更新时间 + public static readonly Field UpdateTime = FindByName("UpdateTime"); + + /// 更新地址 + public static readonly Field UpdateIP = FindByName("UpdateIP"); + + /// 描述 + public static readonly Field Remark = FindByName("Remark"); + + static Field FindByName(String name) => Meta.Table.FindByName(name); + } + + /// 取得租户字段名称的快捷方式 + public partial class __ + { + /// 编号 + public const String Id = "Id"; + + /// 编码。唯一编码 + public const String Code = "Code"; + + /// 名称。显示名称 + public const String Name = "Name"; + + /// 启用 + public const String Enable = "Enable"; + + /// 管理者 + public const String ManagerId = "ManagerId"; + + /// 角色组。租户可选的角色集合,不同级别的租户所拥有的角色不一样,高级功能也会不同 + public const String RoleIds = "RoleIds"; + + /// 图标。附件路径 + public const String Logo = "Logo"; + + /// 数据库。分库用的数据库名 + public const String DatabaseName = "DatabaseName"; + + /// 数据表。分表用的数据表前缀 + public const String TableName = "TableName"; + + /// 过期时间。达到该时间后,自动禁用租户,空表示永不过期 + public const String Expired = "Expired"; + + /// 创建者 + public const String CreateUserId = "CreateUserId"; + + /// 创建时间 + public const String CreateTime = "CreateTime"; + + /// 创建地址 + public const String CreateIP = "CreateIP"; + + /// 更新者 + public const String UpdateUserId = "UpdateUserId"; + + /// 更新时间 + public const String UpdateTime = "UpdateTime"; + + /// 更新地址 + public const String UpdateIP = "UpdateIP"; + + /// 描述 + public const String Remark = "Remark"; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/租户关系.Biz.cs b/XUnitTest.XCode/Code/Entity/租户关系.Biz.cs new file mode 100644 index 000000000..20450c355 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/租户关系.Biz.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using NewLife.Log; +using NewLife.Model; +using NewLife.Reflection; +using NewLife.Threading; +using NewLife.Web; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; +using XCode.Membership; +using XCode.Shards; + +namespace XCode.Membership666; + +public partial class TenantUser : Entity +{ + #region 对象操作 + static TenantUser() + { + // 累加字段,生成 Update xx Set Count=Count+1234 Where xxx + //var df = Meta.Factory.AdditionalFields; + //df.Add(nameof(TenantId)); + + // 过滤器 UserModule、TimeModule、IPModule + Meta.Modules.Add(new UserModule { AllowEmpty = false }); + Meta.Modules.Add(); + Meta.Modules.Add(new IPModule { AllowEmpty = false }); + Meta.Modules.Add(); + + // 实体缓存 + // var ec = Meta.Cache; + // ec.Expire = 60; + } + + /// 验证并修补数据,返回验证结果,或者通过抛出异常的方式提示验证失败。 + /// 添删改方法 + public override Boolean Valid(DataMethod method) + { + //if (method == DataMethod.Delete) return true; + // 如果没有脏数据,则不需要进行任何处理 + if (!HasDirty) return true; + + // 建议先调用基类方法,基类方法会做一些统一处理 + if (!base.Valid(method)) return false; + + // 在新插入数据或者修改了指定字段时进行修正 + + // 处理当前已登录用户信息,可以由UserModule过滤器代劳 + /*var user = ManageProvider.User; + if (user != null) + { + if (method == DataMethod.Insert && !Dirtys[nameof(CreateUserId)]) CreateUserId = user.ID; + if (!Dirtys[nameof(UpdateUserId)]) UpdateUserId = user.ID; + }*/ + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateTime)]) CreateTime = DateTime.Now; + //if (!Dirtys[nameof(UpdateTime)]) UpdateTime = DateTime.Now; + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateIP)]) CreateIP = ManageProvider.UserHost; + //if (!Dirtys[nameof(UpdateIP)]) UpdateIP = ManageProvider.UserHost; + + // 检查唯一索引 + // CheckExist(method == DataMethod.Insert, nameof(TenantId), nameof(UserId)); + + return true; + } + + ///// 首次连接数据库时初始化数据,仅用于实体类重载,用户不应该调用该方法 + //[EditorBrowsable(EditorBrowsableState.Never)] + //protected override void InitData() + //{ + // // InitData一般用于当数据表没有数据时添加一些默认数据,该实体类的任何第一次数据库操作都会触发该方法,默认异步调用 + // if (Meta.Session.Count > 0) return; + + // if (XTrace.Debug) XTrace.WriteLine("开始初始化TenantUser[租户关系]数据……"); + + // var entity = new TenantUser(); + // entity.TenantId = 0; + // entity.UserId = 0; + // entity.Enable = true; + // entity.RoleId = 0; + // entity.RoleIds = "abc"; + // entity.Insert(); + + // if (XTrace.Debug) XTrace.WriteLine("完成初始化TenantUser[租户关系]数据!"); + //} + + ///// 已重载。基类先调用Valid(true)验证数据,然后在事务保护内调用OnInsert + ///// + //public override Int32 Insert() + //{ + // return base.Insert(); + //} + + ///// 已重载。在事务保护范围内处理业务,位于Valid之后 + ///// + //protected override Int32 OnDelete() + //{ + // return base.OnDelete(); + //} + #endregion + + #region 扩展属性 + #endregion + + #region 高级查询 + /// 高级查询 + /// 租户 + /// 用户 + /// 更新时间开始 + /// 更新时间结束 + /// 关键字 + /// 分页参数信息。可携带统计和数据权限扩展查询等信息 + /// 实体列表 + public static IList Search(Int32 tenantId, Int32 userId, DateTime start, DateTime end, String key, PageParameter page) + { + var exp = new WhereExpression(); + + if (tenantId >= 0) exp &= _.TenantId == tenantId; + if (userId >= 0) exp &= _.UserId == userId; + exp &= _.UpdateTime.Between(start, end); + if (!key.IsNullOrEmpty()) exp &= _.RoleIds.Contains(key) | _.CreateIP.Contains(key) | _.UpdateIP.Contains(key) | _.Remark.Contains(key); + + return FindAll(exp, page); + } + + // Select Count(Id) as Id,Category From TenantUser Where CreateTime>'2020-01-24 00:00:00' Group By Category Order By Id Desc limit 20 + //static readonly FieldCache _CategoryCache = new FieldCache(nameof(Category)) + //{ + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + //}; + + ///// 获取类别列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + ///// + //public static IDictionary GetCategoryList() => _CategoryCache.FindAllName(); + #endregion + + #region 业务操作 + public ITenantUser ToModel() + { + var model = new TenantUser(); + model.Copy(this); + + return model; + } + + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/租户关系.cs b/XUnitTest.XCode/Code/Entity/租户关系.cs new file mode 100644 index 000000000..899c68d69 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/租户关系.cs @@ -0,0 +1,361 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; + +namespace XCode.Membership666; + +/// 租户关系。用户选择租户进入系统后,以租户关系角色组替代自有角色组来进行鉴权 +[Serializable] +[DataObject] +[Description("租户关系。用户选择租户进入系统后,以租户关系角色组替代自有角色组来进行鉴权")] +[BindIndex("IU_TenantUser_TenantId_UserId", true, "TenantId,UserId")] +[BindIndex("IX_TenantUser_UserId", false, "UserId")] +[BindTable("TenantUser", Description = "租户关系。用户选择租户进入系统后,以租户关系角色组替代自有角色组来进行鉴权", ConnName = "Membership", DbType = DatabaseType.None)] +public partial class TenantUser : ITenantUser, IEntity +{ + #region 属性 + private Int32 _Id; + /// 编号 + [DisplayName("编号")] + [Description("编号")] + [DataObjectField(true, true, false, 0)] + [BindColumn("Id", "编号", "")] + public Int32 Id { get => _Id; set { if (OnPropertyChanging("Id", value)) { _Id = value; OnPropertyChanged("Id"); } } } + + private Int32 _TenantId; + /// 租户 + [DisplayName("租户")] + [Description("租户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("TenantId", "租户", "")] + public Int32 TenantId { get => _TenantId; set { if (OnPropertyChanging("TenantId", value)) { _TenantId = value; OnPropertyChanged("TenantId"); } } } + + private Int32 _UserId; + /// 用户 + [DisplayName("用户")] + [Description("用户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("UserId", "用户", "")] + public Int32 UserId { get => _UserId; set { if (OnPropertyChanging("UserId", value)) { _UserId = value; OnPropertyChanged("UserId"); } } } + + private Boolean _Enable; + /// 启用 + [DisplayName("启用")] + [Description("启用")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Enable", "启用", "")] + public Boolean Enable { get => _Enable; set { if (OnPropertyChanging("Enable", value)) { _Enable = value; OnPropertyChanged("Enable"); } } } + + private Int32 _RoleId; + /// 角色。用户在该租户所对应的主要角色,替换用户自身的角色组 + [DisplayName("角色")] + [Description("角色。用户在该租户所对应的主要角色,替换用户自身的角色组")] + [DataObjectField(false, false, false, 0)] + [BindColumn("RoleId", "角色。用户在该租户所对应的主要角色,替换用户自身的角色组", "")] + public Int32 RoleId { get => _RoleId; set { if (OnPropertyChanging("RoleId", value)) { _RoleId = value; OnPropertyChanged("RoleId"); } } } + + private String? _RoleIds; + /// 角色组。次要角色集合 + [DisplayName("角色组")] + [Description("角色组。次要角色集合")] + [DataObjectField(false, false, true, 200)] + [BindColumn("RoleIds", "角色组。次要角色集合", "")] + public String? RoleIds { get => _RoleIds; set { if (OnPropertyChanging("RoleIds", value)) { _RoleIds = value; OnPropertyChanged("RoleIds"); } } } + + private Int32 _CreateUserId; + /// 创建者 + [Category("扩展")] + [DisplayName("创建者")] + [Description("创建者")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateUserId", "创建者", "")] + public Int32 CreateUserId { get => _CreateUserId; set { if (OnPropertyChanging("CreateUserId", value)) { _CreateUserId = value; OnPropertyChanged("CreateUserId"); } } } + + private DateTime _CreateTime; + /// 创建时间 + [Category("扩展")] + [DisplayName("创建时间")] + [Description("创建时间")] + [DataObjectField(false, false, true, 0)] + [BindColumn("CreateTime", "创建时间", "")] + public DateTime CreateTime { get => _CreateTime; set { if (OnPropertyChanging("CreateTime", value)) { _CreateTime = value; OnPropertyChanged("CreateTime"); } } } + + private String? _CreateIP; + /// 创建地址 + [Category("扩展")] + [DisplayName("创建地址")] + [Description("创建地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateIP", "创建地址", "")] + public String? CreateIP { get => _CreateIP; set { if (OnPropertyChanging("CreateIP", value)) { _CreateIP = value; OnPropertyChanged("CreateIP"); } } } + + private Int32 _UpdateUserId; + /// 更新者 + [Category("扩展")] + [DisplayName("更新者")] + [Description("更新者")] + [DataObjectField(false, false, false, 0)] + [BindColumn("UpdateUserId", "更新者", "")] + public Int32 UpdateUserId { get => _UpdateUserId; set { if (OnPropertyChanging("UpdateUserId", value)) { _UpdateUserId = value; OnPropertyChanged("UpdateUserId"); } } } + + private DateTime _UpdateTime; + /// 更新时间 + [Category("扩展")] + [DisplayName("更新时间")] + [Description("更新时间")] + [DataObjectField(false, false, true, 0)] + [BindColumn("UpdateTime", "更新时间", "")] + public DateTime UpdateTime { get => _UpdateTime; set { if (OnPropertyChanging("UpdateTime", value)) { _UpdateTime = value; OnPropertyChanged("UpdateTime"); } } } + + private String? _UpdateIP; + /// 更新地址 + [Category("扩展")] + [DisplayName("更新地址")] + [Description("更新地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("UpdateIP", "更新地址", "")] + public String? UpdateIP { get => _UpdateIP; set { if (OnPropertyChanging("UpdateIP", value)) { _UpdateIP = value; OnPropertyChanged("UpdateIP"); } } } + + private String? _Remark; + /// 描述 + [Category("扩展")] + [DisplayName("描述")] + [Description("描述")] + [DataObjectField(false, false, true, 500)] + [BindColumn("Remark", "描述", "")] + public String? Remark { get => _Remark; set { if (OnPropertyChanging("Remark", value)) { _Remark = value; OnPropertyChanged("Remark"); } } } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(ITenantUser model) + { + Id = model.Id; + TenantId = model.TenantId; + UserId = model.UserId; + Enable = model.Enable; + RoleId = model.RoleId; + RoleIds = model.RoleIds; + Remark = model.Remark; + } + #endregion + + #region 获取/设置 字段值 + /// 获取/设置 字段值 + /// 字段名 + /// + public override Object? this[String name] + { + get => name switch + { + "Id" => _Id, + "TenantId" => _TenantId, + "UserId" => _UserId, + "Enable" => _Enable, + "RoleId" => _RoleId, + "RoleIds" => _RoleIds, + "CreateUserId" => _CreateUserId, + "CreateTime" => _CreateTime, + "CreateIP" => _CreateIP, + "UpdateUserId" => _UpdateUserId, + "UpdateTime" => _UpdateTime, + "UpdateIP" => _UpdateIP, + "Remark" => _Remark, + _ => base[name] + }; + set + { + switch (name) + { + case "Id": _Id = value.ToInt(); break; + case "TenantId": _TenantId = value.ToInt(); break; + case "UserId": _UserId = value.ToInt(); break; + case "Enable": _Enable = value.ToBoolean(); break; + case "RoleId": _RoleId = value.ToInt(); break; + case "RoleIds": _RoleIds = Convert.ToString(value); break; + case "CreateUserId": _CreateUserId = value.ToInt(); break; + case "CreateTime": _CreateTime = value.ToDateTime(); break; + case "CreateIP": _CreateIP = Convert.ToString(value); break; + case "UpdateUserId": _UpdateUserId = value.ToInt(); break; + case "UpdateTime": _UpdateTime = value.ToDateTime(); break; + case "UpdateIP": _UpdateIP = Convert.ToString(value); break; + case "Remark": _Remark = Convert.ToString(value); break; + default: base[name] = value; break; + } + } + } + #endregion + + #region 关联映射 + /// 租户 + [XmlIgnore, IgnoreDataMember, ScriptIgnore] + public Tenant? Tenant => Extends.Get(nameof(Tenant), k => Tenant.FindById(TenantId)); + + /// 租户 + [Map(nameof(TenantId), typeof(Tenant), "Id")] + public String? TenantName => Tenant?.ToString(); + + /// 用户 + [XmlIgnore, IgnoreDataMember, ScriptIgnore] + public User? User => Extends.Get(nameof(User), k => User.FindByID(UserId)); + + /// 用户 + [Map(nameof(UserId), typeof(User), "ID")] + public String? UserName => User?.ToString(); + + /// 角色 + [XmlIgnore, IgnoreDataMember, ScriptIgnore] + public Role? Role => Extends.Get(nameof(Role), k => Role.FindByID(RoleId)); + + /// 角色 + [Map(nameof(RoleId), typeof(Role), "ID")] + public String? RoleName => Role?.Name; + + #endregion + + #region 扩展查询 + /// 根据编号查找 + /// 编号 + /// 实体对象 + public static TenantUser FindById(Int32 id) + { + if (id < 0) return null; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.Id == id); + + // 单对象缓存 + return Meta.SingleCache[id]; + + //return Find(_.Id == id); + } + + /// 根据租户、用户查找 + /// 租户 + /// 用户 + /// 实体对象 + public static TenantUser FindByTenantIdAndUserId(Int32 tenantId, Int32 userId) + { + if (tenantId < 0) return null; + if (userId < 0) return null; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.TenantId == tenantId && e.UserId == userId); + + return Find(_.TenantId == tenantId & _.UserId == userId); + } + + /// 根据用户查找 + /// 用户 + /// 实体列表 + public static IList FindAllByUserId(Int32 userId) + { + if (userId < 0) return []; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.UserId == userId); + + return FindAll(_.UserId == userId); + } + #endregion + + #region 字段名 + /// 取得租户关系字段信息的快捷方式 + public partial class _ + { + /// 编号 + public static readonly Field Id = FindByName("Id"); + + /// 租户 + public static readonly Field TenantId = FindByName("TenantId"); + + /// 用户 + public static readonly Field UserId = FindByName("UserId"); + + /// 启用 + public static readonly Field Enable = FindByName("Enable"); + + /// 角色。用户在该租户所对应的主要角色,替换用户自身的角色组 + public static readonly Field RoleId = FindByName("RoleId"); + + /// 角色组。次要角色集合 + public static readonly Field RoleIds = FindByName("RoleIds"); + + /// 创建者 + public static readonly Field CreateUserId = FindByName("CreateUserId"); + + /// 创建时间 + public static readonly Field CreateTime = FindByName("CreateTime"); + + /// 创建地址 + public static readonly Field CreateIP = FindByName("CreateIP"); + + /// 更新者 + public static readonly Field UpdateUserId = FindByName("UpdateUserId"); + + /// 更新时间 + public static readonly Field UpdateTime = FindByName("UpdateTime"); + + /// 更新地址 + public static readonly Field UpdateIP = FindByName("UpdateIP"); + + /// 描述 + public static readonly Field Remark = FindByName("Remark"); + + static Field FindByName(String name) => Meta.Table.FindByName(name); + } + + /// 取得租户关系字段名称的快捷方式 + public partial class __ + { + /// 编号 + public const String Id = "Id"; + + /// 租户 + public const String TenantId = "TenantId"; + + /// 用户 + public const String UserId = "UserId"; + + /// 启用 + public const String Enable = "Enable"; + + /// 角色。用户在该租户所对应的主要角色,替换用户自身的角色组 + public const String RoleId = "RoleId"; + + /// 角色组。次要角色集合 + public const String RoleIds = "RoleIds"; + + /// 创建者 + public const String CreateUserId = "CreateUserId"; + + /// 创建时间 + public const String CreateTime = "CreateTime"; + + /// 创建地址 + public const String CreateIP = "CreateIP"; + + /// 更新者 + public const String UpdateUserId = "UpdateUserId"; + + /// 更新时间 + public const String UpdateTime = "UpdateTime"; + + /// 更新地址 + public const String UpdateIP = "UpdateIP"; + + /// 描述 + public const String Remark = "Remark"; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/菜单.Biz.cs b/XUnitTest.XCode/Code/Entity/菜单.Biz.cs new file mode 100644 index 000000000..bdd4e002c --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/菜单.Biz.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using NewLife.Log; +using NewLife.Model; +using NewLife.Reflection; +using NewLife.Threading; +using NewLife.Web; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; +using XCode.Membership; +using XCode.Shards; + +namespace XCode.Membership666; + +public partial class Menu : Entity +{ + #region 对象操作 + static Menu() + { + // 累加字段,生成 Update xx Set Count=Count+1234 Where xxx + //var df = Meta.Factory.AdditionalFields; + //df.Add(nameof(ParentID)); + + // 过滤器 UserModule、TimeModule、IPModule + Meta.Modules.Add(new UserModule { AllowEmpty = false }); + Meta.Modules.Add(); + Meta.Modules.Add(new IPModule { AllowEmpty = false }); + + // 实体缓存 + // var ec = Meta.Cache; + // ec.Expire = 60; + } + + /// 验证并修补数据,返回验证结果,或者通过抛出异常的方式提示验证失败。 + /// 添删改方法 + public override Boolean Valid(DataMethod method) + { + //if (method == DataMethod.Delete) return true; + // 如果没有脏数据,则不需要进行任何处理 + if (!HasDirty) return true; + + // 这里验证参数范围,建议抛出参数异常,指定参数名,前端用户界面可以捕获参数异常并聚焦到对应的参数输入框 + if (Name.IsNullOrEmpty()) throw new ArgumentNullException(nameof(Name), "名称不能为空!"); + + // 建议先调用基类方法,基类方法会做一些统一处理 + if (!base.Valid(method)) return false; + + // 在新插入数据或者修改了指定字段时进行修正 + + // 保留2位小数 + //Ex3 = Math.Round(Ex3, 2); + + // 处理当前已登录用户信息,可以由UserModule过滤器代劳 + /*var user = ManageProvider.User; + if (user != null) + { + if (method == DataMethod.Insert && !Dirtys[nameof(CreateUserID)]) CreateUserID = user.ID; + if (!Dirtys[nameof(UpdateUserID)]) UpdateUserID = user.ID; + }*/ + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateTime)]) CreateTime = DateTime.Now; + //if (!Dirtys[nameof(UpdateTime)]) UpdateTime = DateTime.Now; + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateIP)]) CreateIP = ManageProvider.UserHost; + //if (!Dirtys[nameof(UpdateIP)]) UpdateIP = ManageProvider.UserHost; + + // 检查唯一索引 + // CheckExist(method == DataMethod.Insert, nameof(ParentID), nameof(Name)); + + return true; + } + + ///// 首次连接数据库时初始化数据,仅用于实体类重载,用户不应该调用该方法 + //[EditorBrowsable(EditorBrowsableState.Never)] + //protected override void InitData() + //{ + // // InitData一般用于当数据表没有数据时添加一些默认数据,该实体类的任何第一次数据库操作都会触发该方法,默认异步调用 + // if (Meta.Session.Count > 0) return; + + // if (XTrace.Debug) XTrace.WriteLine("开始初始化Menu[菜单]数据……"); + + // var entity = new Menu(); + // entity.Name = "abc"; + // entity.DisplayName = "abc"; + // entity.FullName = "abc"; + // entity.ParentID = 0; + // entity.Url = "abc"; + // entity.Sort = 0; + // entity.Icon = "abc"; + // entity.Visible = true; + // entity.Necessary = true; + // entity.NewWindow = true; + // entity.Permission = "abc"; + // entity.Ex1 = 0; + // entity.Ex2 = 0; + // entity.Ex3 = 0.0; + // entity.Ex4 = "abc"; + // entity.Ex5 = "abc"; + // entity.Ex6 = "abc"; + // entity.Insert(); + + // if (XTrace.Debug) XTrace.WriteLine("完成初始化Menu[菜单]数据!"); + //} + + ///// 已重载。基类先调用Valid(true)验证数据,然后在事务保护内调用OnInsert + ///// + //public override Int32 Insert() + //{ + // return base.Insert(); + //} + + ///// 已重载。在事务保护范围内处理业务,位于Valid之后 + ///// + //protected override Int32 OnDelete() + //{ + // return base.OnDelete(); + //} + #endregion + + #region 扩展属性 + #endregion + + #region 高级查询 + /// 高级查询 + /// 名称 + /// 父编号 + /// 更新时间开始 + /// 更新时间结束 + /// 关键字 + /// 分页参数信息。可携带统计和数据权限扩展查询等信息 + /// 实体列表 + public static IList Search(String name, Int32 parentId, DateTime start, DateTime end, String key, PageParameter page) + { + var exp = new WhereExpression(); + + if (!name.IsNullOrEmpty()) exp &= _.Name == name; + if (parentId >= 0) exp &= _.ParentID == parentId; + exp &= _.UpdateTime.Between(start, end); + if (!key.IsNullOrEmpty()) exp &= _.Name.Contains(key) | _.DisplayName.Contains(key) | _.FullName.Contains(key) | _.Url.Contains(key) | _.Icon.Contains(key) | _.Permission.Contains(key) | _.Ex4.Contains(key) | _.Ex5.Contains(key) | _.Ex6.Contains(key) | _.CreateUser.Contains(key) | _.CreateIP.Contains(key) | _.UpdateUser.Contains(key) | _.UpdateIP.Contains(key) | _.Remark.Contains(key); + + return FindAll(exp, page); + } + + // Select Count(ID) as ID,Category From Menu Where CreateTime>'2020-01-24 00:00:00' Group By Category Order By ID Desc limit 20 + //static readonly FieldCache _CategoryCache = new FieldCache(nameof(Category)) + //{ + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + //}; + + ///// 获取类别列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + ///// + //public static IDictionary GetCategoryList() => _CategoryCache.FindAllName(); + #endregion + + #region 业务操作 + public IMenu ToModel() + { + var model = new Menu(); + model.Copy(this); + + return model; + } + + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/菜单.cs b/XUnitTest.XCode/Code/Entity/菜单.cs new file mode 100644 index 000000000..0d79de240 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/菜单.cs @@ -0,0 +1,589 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; + +namespace XCode.Membership666; + +/// 菜单 +[Serializable] +[DataObject] +[Description("菜单")] +[BindIndex("IX_Menu_Name", false, "Name")] +[BindIndex("IU_Menu_ParentID_Name", true, "ParentID,Name")] +[BindTable("Menu", Description = "菜单", ConnName = "Membership", DbType = DatabaseType.None)] +public partial class Menu : IMenu, IEntity +{ + #region 属性 + private Int32 _ID; + /// 编号 + [DisplayName("编号")] + [Description("编号")] + [DataObjectField(true, true, false, 0)] + [BindColumn("ID", "编号", "")] + public Int32 ID { get => _ID; set { if (OnPropertyChanging("ID", value)) { _ID = value; OnPropertyChanged("ID"); } } } + + private String _Name = null!; + /// 名称 + [DisplayName("名称")] + [Description("名称")] + [DataObjectField(false, false, false, 50)] + [BindColumn("Name", "名称", "", Master = true)] + public String Name { get => _Name; set { if (OnPropertyChanging("Name", value)) { _Name = value; OnPropertyChanged("Name"); } } } + + private String? _DisplayName; + /// 显示名 + [DisplayName("显示名")] + [Description("显示名")] + [DataObjectField(false, false, true, 50)] + [BindColumn("DisplayName", "显示名", "")] + public String? DisplayName { get => _DisplayName; set { if (OnPropertyChanging("DisplayName", value)) { _DisplayName = value; OnPropertyChanged("DisplayName"); } } } + + private String? _FullName; + /// 全名 + [DisplayName("全名")] + [Description("全名")] + [DataObjectField(false, false, true, 200)] + [BindColumn("FullName", "全名", "")] + public String? FullName { get => _FullName; set { if (OnPropertyChanging("FullName", value)) { _FullName = value; OnPropertyChanged("FullName"); } } } + + private Int32 _ParentID; + /// 父编号 + [DisplayName("父编号")] + [Description("父编号")] + [DataObjectField(false, false, false, 0)] + [BindColumn("ParentID", "父编号", "")] + public Int32 ParentID { get => _ParentID; set { if (OnPropertyChanging("ParentID", value)) { _ParentID = value; OnPropertyChanged("ParentID"); } } } + + private String? _Url; + /// 链接 + [DisplayName("链接")] + [Description("链接")] + [DataObjectField(false, false, true, 200)] + [BindColumn("Url", "链接", "")] + public String? Url { get => _Url; set { if (OnPropertyChanging("Url", value)) { _Url = value; OnPropertyChanged("Url"); } } } + + private Int32 _Sort; + /// 排序 + [DisplayName("排序")] + [Description("排序")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Sort", "排序", "")] + public Int32 Sort { get => _Sort; set { if (OnPropertyChanging("Sort", value)) { _Sort = value; OnPropertyChanged("Sort"); } } } + + private String? _Icon; + /// 图标 + [DisplayName("图标")] + [Description("图标")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Icon", "图标", "")] + public String? Icon { get => _Icon; set { if (OnPropertyChanging("Icon", value)) { _Icon = value; OnPropertyChanged("Icon"); } } } + + private Boolean _Visible; + /// 可见 + [DisplayName("可见")] + [Description("可见")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Visible", "可见", "")] + public Boolean Visible { get => _Visible; set { if (OnPropertyChanging("Visible", value)) { _Visible = value; OnPropertyChanged("Visible"); } } } + + private Boolean _Necessary; + /// 必要。必要的菜单,必须至少有角色拥有这些权限,如果没有则自动授权给系统角色 + [DisplayName("必要")] + [Description("必要。必要的菜单,必须至少有角色拥有这些权限,如果没有则自动授权给系统角色")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Necessary", "必要。必要的菜单,必须至少有角色拥有这些权限,如果没有则自动授权给系统角色", "")] + public Boolean Necessary { get => _Necessary; set { if (OnPropertyChanging("Necessary", value)) { _Necessary = value; OnPropertyChanged("Necessary"); } } } + + private Boolean _NewWindow; + /// 新窗口。新窗口打开链接 + [DisplayName("新窗口")] + [Description("新窗口。新窗口打开链接")] + [DataObjectField(false, false, false, 0)] + [BindColumn("NewWindow", "新窗口。新窗口打开链接", "")] + public Boolean NewWindow { get => _NewWindow; set { if (OnPropertyChanging("NewWindow", value)) { _NewWindow = value; OnPropertyChanged("NewWindow"); } } } + + private String? _Permission; + /// 权限子项。逗号分隔,每个权限子项名值竖线分隔 + [DisplayName("权限子项")] + [Description("权限子项。逗号分隔,每个权限子项名值竖线分隔")] + [DataObjectField(false, false, true, 200)] + [BindColumn("Permission", "权限子项。逗号分隔,每个权限子项名值竖线分隔", "")] + public String? Permission { get => _Permission; set { if (OnPropertyChanging("Permission", value)) { _Permission = value; OnPropertyChanged("Permission"); } } } + + private Int32 _Ex1; + /// 扩展1 + [Category("扩展")] + [DisplayName("扩展1")] + [Description("扩展1")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex1", "扩展1", "")] + public Int32 Ex1 { get => _Ex1; set { if (OnPropertyChanging("Ex1", value)) { _Ex1 = value; OnPropertyChanged("Ex1"); } } } + + private Int32 _Ex2; + /// 扩展2 + [Category("扩展")] + [DisplayName("扩展2")] + [Description("扩展2")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex2", "扩展2", "")] + public Int32 Ex2 { get => _Ex2; set { if (OnPropertyChanging("Ex2", value)) { _Ex2 = value; OnPropertyChanged("Ex2"); } } } + + private Double _Ex3; + /// 扩展3 + [Category("扩展")] + [DisplayName("扩展3")] + [Description("扩展3")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex3", "扩展3", "")] + public Double Ex3 { get => _Ex3; set { if (OnPropertyChanging("Ex3", value)) { _Ex3 = value; OnPropertyChanged("Ex3"); } } } + + private String? _Ex4; + /// 扩展4 + [Category("扩展")] + [DisplayName("扩展4")] + [Description("扩展4")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex4", "扩展4", "")] + public String? Ex4 { get => _Ex4; set { if (OnPropertyChanging("Ex4", value)) { _Ex4 = value; OnPropertyChanged("Ex4"); } } } + + private String? _Ex5; + /// 扩展5 + [Category("扩展")] + [DisplayName("扩展5")] + [Description("扩展5")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex5", "扩展5", "")] + public String? Ex5 { get => _Ex5; set { if (OnPropertyChanging("Ex5", value)) { _Ex5 = value; OnPropertyChanged("Ex5"); } } } + + private String? _Ex6; + /// 扩展6 + [Category("扩展")] + [DisplayName("扩展6")] + [Description("扩展6")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex6", "扩展6", "")] + public String? Ex6 { get => _Ex6; set { if (OnPropertyChanging("Ex6", value)) { _Ex6 = value; OnPropertyChanged("Ex6"); } } } + + private String? _CreateUser; + /// 创建者 + [Category("扩展")] + [DisplayName("创建者")] + [Description("创建者")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateUser", "创建者", "")] + public String? CreateUser { get => _CreateUser; set { if (OnPropertyChanging("CreateUser", value)) { _CreateUser = value; OnPropertyChanged("CreateUser"); } } } + + private Int32 _CreateUserID; + /// 创建用户 + [Category("扩展")] + [DisplayName("创建用户")] + [Description("创建用户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateUserID", "创建用户", "")] + public Int32 CreateUserID { get => _CreateUserID; set { if (OnPropertyChanging("CreateUserID", value)) { _CreateUserID = value; OnPropertyChanged("CreateUserID"); } } } + + private String? _CreateIP; + /// 创建地址 + [Category("扩展")] + [DisplayName("创建地址")] + [Description("创建地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateIP", "创建地址", "")] + public String? CreateIP { get => _CreateIP; set { if (OnPropertyChanging("CreateIP", value)) { _CreateIP = value; OnPropertyChanged("CreateIP"); } } } + + private DateTime _CreateTime; + /// 创建时间 + [Category("扩展")] + [DisplayName("创建时间")] + [Description("创建时间")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateTime", "创建时间", "")] + public DateTime CreateTime { get => _CreateTime; set { if (OnPropertyChanging("CreateTime", value)) { _CreateTime = value; OnPropertyChanged("CreateTime"); } } } + + private String? _UpdateUser; + /// 更新者 + [Category("扩展")] + [DisplayName("更新者")] + [Description("更新者")] + [DataObjectField(false, false, true, 50)] + [BindColumn("UpdateUser", "更新者", "")] + public String? UpdateUser { get => _UpdateUser; set { if (OnPropertyChanging("UpdateUser", value)) { _UpdateUser = value; OnPropertyChanged("UpdateUser"); } } } + + private Int32 _UpdateUserID; + /// 更新用户 + [Category("扩展")] + [DisplayName("更新用户")] + [Description("更新用户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("UpdateUserID", "更新用户", "")] + public Int32 UpdateUserID { get => _UpdateUserID; set { if (OnPropertyChanging("UpdateUserID", value)) { _UpdateUserID = value; OnPropertyChanged("UpdateUserID"); } } } + + private String? _UpdateIP; + /// 更新地址 + [Category("扩展")] + [DisplayName("更新地址")] + [Description("更新地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("UpdateIP", "更新地址", "")] + public String? UpdateIP { get => _UpdateIP; set { if (OnPropertyChanging("UpdateIP", value)) { _UpdateIP = value; OnPropertyChanged("UpdateIP"); } } } + + private DateTime _UpdateTime; + /// 更新时间 + [Category("扩展")] + [DisplayName("更新时间")] + [Description("更新时间")] + [DataObjectField(false, false, false, 0)] + [BindColumn("UpdateTime", "更新时间", "")] + public DateTime UpdateTime { get => _UpdateTime; set { if (OnPropertyChanging("UpdateTime", value)) { _UpdateTime = value; OnPropertyChanged("UpdateTime"); } } } + + private String? _Remark; + /// 备注 + [Category("扩展")] + [DisplayName("备注")] + [Description("备注")] + [DataObjectField(false, false, true, 500)] + [BindColumn("Remark", "备注", "")] + public String? Remark { get => _Remark; set { if (OnPropertyChanging("Remark", value)) { _Remark = value; OnPropertyChanged("Remark"); } } } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IMenu model) + { + ID = model.ID; + Name = model.Name; + DisplayName = model.DisplayName; + FullName = model.FullName; + ParentID = model.ParentID; + Url = model.Url; + Sort = model.Sort; + Icon = model.Icon; + Visible = model.Visible; + Necessary = model.Necessary; + NewWindow = model.NewWindow; + Permission = model.Permission; + Ex1 = model.Ex1; + Ex2 = model.Ex2; + Ex3 = model.Ex3; + Ex4 = model.Ex4; + Ex5 = model.Ex5; + Ex6 = model.Ex6; + CreateUser = model.CreateUser; + CreateUserID = model.CreateUserID; + CreateIP = model.CreateIP; + CreateTime = model.CreateTime; + UpdateUser = model.UpdateUser; + UpdateUserID = model.UpdateUserID; + UpdateIP = model.UpdateIP; + UpdateTime = model.UpdateTime; + Remark = model.Remark; + } + #endregion + + #region 获取/设置 字段值 + /// 获取/设置 字段值 + /// 字段名 + /// + public override Object? this[String name] + { + get => name switch + { + "ID" => _ID, + "Name" => _Name, + "DisplayName" => _DisplayName, + "FullName" => _FullName, + "ParentID" => _ParentID, + "Url" => _Url, + "Sort" => _Sort, + "Icon" => _Icon, + "Visible" => _Visible, + "Necessary" => _Necessary, + "NewWindow" => _NewWindow, + "Permission" => _Permission, + "Ex1" => _Ex1, + "Ex2" => _Ex2, + "Ex3" => _Ex3, + "Ex4" => _Ex4, + "Ex5" => _Ex5, + "Ex6" => _Ex6, + "CreateUser" => _CreateUser, + "CreateUserID" => _CreateUserID, + "CreateIP" => _CreateIP, + "CreateTime" => _CreateTime, + "UpdateUser" => _UpdateUser, + "UpdateUserID" => _UpdateUserID, + "UpdateIP" => _UpdateIP, + "UpdateTime" => _UpdateTime, + "Remark" => _Remark, + _ => base[name] + }; + set + { + switch (name) + { + case "ID": _ID = value.ToInt(); break; + case "Name": _Name = Convert.ToString(value); break; + case "DisplayName": _DisplayName = Convert.ToString(value); break; + case "FullName": _FullName = Convert.ToString(value); break; + case "ParentID": _ParentID = value.ToInt(); break; + case "Url": _Url = Convert.ToString(value); break; + case "Sort": _Sort = value.ToInt(); break; + case "Icon": _Icon = Convert.ToString(value); break; + case "Visible": _Visible = value.ToBoolean(); break; + case "Necessary": _Necessary = value.ToBoolean(); break; + case "NewWindow": _NewWindow = value.ToBoolean(); break; + case "Permission": _Permission = Convert.ToString(value); break; + case "Ex1": _Ex1 = value.ToInt(); break; + case "Ex2": _Ex2 = value.ToInt(); break; + case "Ex3": _Ex3 = value.ToDouble(); break; + case "Ex4": _Ex4 = Convert.ToString(value); break; + case "Ex5": _Ex5 = Convert.ToString(value); break; + case "Ex6": _Ex6 = Convert.ToString(value); break; + case "CreateUser": _CreateUser = Convert.ToString(value); break; + case "CreateUserID": _CreateUserID = value.ToInt(); break; + case "CreateIP": _CreateIP = Convert.ToString(value); break; + case "CreateTime": _CreateTime = value.ToDateTime(); break; + case "UpdateUser": _UpdateUser = Convert.ToString(value); break; + case "UpdateUserID": _UpdateUserID = value.ToInt(); break; + case "UpdateIP": _UpdateIP = Convert.ToString(value); break; + case "UpdateTime": _UpdateTime = value.ToDateTime(); break; + case "Remark": _Remark = Convert.ToString(value); break; + default: base[name] = value; break; + } + } + } + #endregion + + #region 关联映射 + #endregion + + #region 扩展查询 + /// 根据编号查找 + /// 编号 + /// 实体对象 + public static Menu FindByID(Int32 id) + { + if (id < 0) return null; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.ID == id); + + // 单对象缓存 + return Meta.SingleCache[id]; + + //return Find(_.ID == id); + } + + /// 根据名称查找 + /// 名称 + /// 实体列表 + public static IList FindAllByName(String name) + { + if (name.IsNullOrEmpty()) return []; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.Name.EqualIgnoreCase(name)); + + return FindAll(_.Name == name); + } + + /// 根据父编号、名称查找 + /// 父编号 + /// 名称 + /// 实体对象 + public static Menu FindByParentIDAndName(Int32 parentId, String name) + { + if (parentId < 0) return null; + if (name.IsNullOrEmpty()) return null; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.ParentID == parentId && e.Name.EqualIgnoreCase(name)); + + return Find(_.ParentID == parentId & _.Name == name); + } + #endregion + + #region 字段名 + /// 取得菜单字段信息的快捷方式 + public partial class _ + { + /// 编号 + public static readonly Field ID = FindByName("ID"); + + /// 名称 + public static readonly Field Name = FindByName("Name"); + + /// 显示名 + public static readonly Field DisplayName = FindByName("DisplayName"); + + /// 全名 + public static readonly Field FullName = FindByName("FullName"); + + /// 父编号 + public static readonly Field ParentID = FindByName("ParentID"); + + /// 链接 + public static readonly Field Url = FindByName("Url"); + + /// 排序 + public static readonly Field Sort = FindByName("Sort"); + + /// 图标 + public static readonly Field Icon = FindByName("Icon"); + + /// 可见 + public static readonly Field Visible = FindByName("Visible"); + + /// 必要。必要的菜单,必须至少有角色拥有这些权限,如果没有则自动授权给系统角色 + public static readonly Field Necessary = FindByName("Necessary"); + + /// 新窗口。新窗口打开链接 + public static readonly Field NewWindow = FindByName("NewWindow"); + + /// 权限子项。逗号分隔,每个权限子项名值竖线分隔 + public static readonly Field Permission = FindByName("Permission"); + + /// 扩展1 + public static readonly Field Ex1 = FindByName("Ex1"); + + /// 扩展2 + public static readonly Field Ex2 = FindByName("Ex2"); + + /// 扩展3 + public static readonly Field Ex3 = FindByName("Ex3"); + + /// 扩展4 + public static readonly Field Ex4 = FindByName("Ex4"); + + /// 扩展5 + public static readonly Field Ex5 = FindByName("Ex5"); + + /// 扩展6 + public static readonly Field Ex6 = FindByName("Ex6"); + + /// 创建者 + public static readonly Field CreateUser = FindByName("CreateUser"); + + /// 创建用户 + public static readonly Field CreateUserID = FindByName("CreateUserID"); + + /// 创建地址 + public static readonly Field CreateIP = FindByName("CreateIP"); + + /// 创建时间 + public static readonly Field CreateTime = FindByName("CreateTime"); + + /// 更新者 + public static readonly Field UpdateUser = FindByName("UpdateUser"); + + /// 更新用户 + public static readonly Field UpdateUserID = FindByName("UpdateUserID"); + + /// 更新地址 + public static readonly Field UpdateIP = FindByName("UpdateIP"); + + /// 更新时间 + public static readonly Field UpdateTime = FindByName("UpdateTime"); + + /// 备注 + public static readonly Field Remark = FindByName("Remark"); + + static Field FindByName(String name) => Meta.Table.FindByName(name); + } + + /// 取得菜单字段名称的快捷方式 + public partial class __ + { + /// 编号 + public const String ID = "ID"; + + /// 名称 + public const String Name = "Name"; + + /// 显示名 + public const String DisplayName = "DisplayName"; + + /// 全名 + public const String FullName = "FullName"; + + /// 父编号 + public const String ParentID = "ParentID"; + + /// 链接 + public const String Url = "Url"; + + /// 排序 + public const String Sort = "Sort"; + + /// 图标 + public const String Icon = "Icon"; + + /// 可见 + public const String Visible = "Visible"; + + /// 必要。必要的菜单,必须至少有角色拥有这些权限,如果没有则自动授权给系统角色 + public const String Necessary = "Necessary"; + + /// 新窗口。新窗口打开链接 + public const String NewWindow = "NewWindow"; + + /// 权限子项。逗号分隔,每个权限子项名值竖线分隔 + public const String Permission = "Permission"; + + /// 扩展1 + public const String Ex1 = "Ex1"; + + /// 扩展2 + public const String Ex2 = "Ex2"; + + /// 扩展3 + public const String Ex3 = "Ex3"; + + /// 扩展4 + public const String Ex4 = "Ex4"; + + /// 扩展5 + public const String Ex5 = "Ex5"; + + /// 扩展6 + public const String Ex6 = "Ex6"; + + /// 创建者 + public const String CreateUser = "CreateUser"; + + /// 创建用户 + public const String CreateUserID = "CreateUserID"; + + /// 创建地址 + public const String CreateIP = "CreateIP"; + + /// 创建时间 + public const String CreateTime = "CreateTime"; + + /// 更新者 + public const String UpdateUser = "UpdateUser"; + + /// 更新用户 + public const String UpdateUserID = "UpdateUserID"; + + /// 更新地址 + public const String UpdateIP = "UpdateIP"; + + /// 更新时间 + public const String UpdateTime = "UpdateTime"; + + /// 备注 + public const String Remark = "Remark"; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/角色.Biz.cs b/XUnitTest.XCode/Code/Entity/角色.Biz.cs new file mode 100644 index 000000000..1847b5276 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/角色.Biz.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using NewLife.Log; +using NewLife.Model; +using NewLife.Reflection; +using NewLife.Threading; +using NewLife.Web; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; +using XCode.Membership; +using XCode.Shards; + +namespace XCode.Membership666; + +public partial class Role : Entity +{ + #region 对象操作 + static Role() + { + // 累加字段,生成 Update xx Set Count=Count+1234 Where xxx + //var df = Meta.Factory.AdditionalFields; + //df.Add(nameof(Sort)); + + // 过滤器 UserModule、TimeModule、IPModule + Meta.Modules.Add(new UserModule { AllowEmpty = false }); + Meta.Modules.Add(); + Meta.Modules.Add(new IPModule { AllowEmpty = false }); + + // 实体缓存 + // var ec = Meta.Cache; + // ec.Expire = 60; + + // 单对象缓存 + var sc = Meta.SingleCache; + // sc.Expire = 60; + sc.FindSlaveKeyMethod = k => Find(_.Name == k); + sc.GetSlaveKeyMethod = e => e.Name; + } + + /// 验证并修补数据,返回验证结果,或者通过抛出异常的方式提示验证失败。 + /// 添删改方法 + public override Boolean Valid(DataMethod method) + { + //if (method == DataMethod.Delete) return true; + // 如果没有脏数据,则不需要进行任何处理 + if (!HasDirty) return true; + + // 这里验证参数范围,建议抛出参数异常,指定参数名,前端用户界面可以捕获参数异常并聚焦到对应的参数输入框 + if (Name.IsNullOrEmpty()) throw new ArgumentNullException(nameof(Name), "名称不能为空!"); + + // 建议先调用基类方法,基类方法会做一些统一处理 + if (!base.Valid(method)) return false; + + // 在新插入数据或者修改了指定字段时进行修正 + + // 保留2位小数 + //Ex3 = Math.Round(Ex3, 2); + + // 处理当前已登录用户信息,可以由UserModule过滤器代劳 + /*var user = ManageProvider.User; + if (user != null) + { + if (method == DataMethod.Insert && !Dirtys[nameof(CreateUserID)]) CreateUserID = user.ID; + if (!Dirtys[nameof(UpdateUserID)]) UpdateUserID = user.ID; + }*/ + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateTime)]) CreateTime = DateTime.Now; + //if (!Dirtys[nameof(UpdateTime)]) UpdateTime = DateTime.Now; + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateIP)]) CreateIP = ManageProvider.UserHost; + //if (!Dirtys[nameof(UpdateIP)]) UpdateIP = ManageProvider.UserHost; + + // 检查唯一索引 + // CheckExist(method == DataMethod.Insert, nameof(Name)); + + return true; + } + + ///// 首次连接数据库时初始化数据,仅用于实体类重载,用户不应该调用该方法 + //[EditorBrowsable(EditorBrowsableState.Never)] + //protected override void InitData() + //{ + // // InitData一般用于当数据表没有数据时添加一些默认数据,该实体类的任何第一次数据库操作都会触发该方法,默认异步调用 + // if (Meta.Session.Count > 0) return; + + // if (XTrace.Debug) XTrace.WriteLine("开始初始化Role[角色]数据……"); + + // var entity = new Role(); + // entity.Name = "abc"; + // entity.Enable = true; + // entity.IsSystem = true; + // entity.Permission = "abc"; + // entity.Sort = 0; + // entity.Ex1 = 0; + // entity.Ex2 = 0; + // entity.Ex3 = 0.0; + // entity.Ex4 = "abc"; + // entity.Ex5 = "abc"; + // entity.Ex6 = "abc"; + // entity.Insert(); + + // if (XTrace.Debug) XTrace.WriteLine("完成初始化Role[角色]数据!"); + //} + + ///// 已重载。基类先调用Valid(true)验证数据,然后在事务保护内调用OnInsert + ///// + //public override Int32 Insert() + //{ + // return base.Insert(); + //} + + ///// 已重载。在事务保护范围内处理业务,位于Valid之后 + ///// + //protected override Int32 OnDelete() + //{ + // return base.OnDelete(); + //} + #endregion + + #region 扩展属性 + #endregion + + #region 高级查询 + /// 高级查询 + /// 名称 + /// 更新时间开始 + /// 更新时间结束 + /// 关键字 + /// 分页参数信息。可携带统计和数据权限扩展查询等信息 + /// 实体列表 + public static IList Search(String name, DateTime start, DateTime end, String key, PageParameter page) + { + var exp = new WhereExpression(); + + if (!name.IsNullOrEmpty()) exp &= _.Name == name; + exp &= _.UpdateTime.Between(start, end); + if (!key.IsNullOrEmpty()) exp &= _.Name.Contains(key) | _.Permission.Contains(key) | _.Ex4.Contains(key) | _.Ex5.Contains(key) | _.Ex6.Contains(key) | _.CreateUser.Contains(key) | _.CreateIP.Contains(key) | _.UpdateUser.Contains(key) | _.UpdateIP.Contains(key) | _.Remark.Contains(key); + + return FindAll(exp, page); + } + + // Select Count(ID) as ID,Category From Role Where CreateTime>'2020-01-24 00:00:00' Group By Category Order By ID Desc limit 20 + //static readonly FieldCache _CategoryCache = new FieldCache(nameof(Category)) + //{ + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + //}; + + ///// 获取类别列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + ///// + //public static IDictionary GetCategoryList() => _CategoryCache.FindAllName(); + #endregion + + #region 业务操作 + public IRole ToModel() + { + var model = new Role(); + model.Copy(this); + + return model; + } + + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/角色.cs b/XUnitTest.XCode/Code/Entity/角色.cs new file mode 100644 index 000000000..dbb5a6907 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/角色.cs @@ -0,0 +1,474 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; + +namespace XCode.Membership666; + +/// 角色 +[Serializable] +[DataObject] +[Description("角色")] +[BindIndex("IU_Role_Name", true, "Name")] +[BindTable("Role", Description = "角色", ConnName = "Membership", DbType = DatabaseType.None)] +public partial class Role : IRole, IEntity +{ + #region 属性 + private Int32 _ID; + /// 编号 + [DisplayName("编号")] + [Description("编号")] + [DataObjectField(true, true, false, 0)] + [BindColumn("ID", "编号", "")] + public Int32 ID { get => _ID; set { if (OnPropertyChanging("ID", value)) { _ID = value; OnPropertyChanged("ID"); } } } + + private String _Name = null!; + /// 名称 + [DisplayName("名称")] + [Description("名称")] + [DataObjectField(false, false, false, 50)] + [BindColumn("Name", "名称", "", Master = true)] + public String Name { get => _Name; set { if (OnPropertyChanging("Name", value)) { _Name = value; OnPropertyChanged("Name"); } } } + + private Boolean _Enable; + /// 启用 + [DisplayName("启用")] + [Description("启用")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Enable", "启用", "")] + public Boolean Enable { get => _Enable; set { if (OnPropertyChanging("Enable", value)) { _Enable = value; OnPropertyChanged("Enable"); } } } + + private Boolean _IsSystem; + /// 系统。用于业务系统开发使用,不受数据权限约束,禁止修改名称或删除 + [DisplayName("系统")] + [Description("系统。用于业务系统开发使用,不受数据权限约束,禁止修改名称或删除")] + [DataObjectField(false, false, false, 0)] + [BindColumn("IsSystem", "系统。用于业务系统开发使用,不受数据权限约束,禁止修改名称或删除", "")] + public Boolean IsSystem { get => _IsSystem; set { if (OnPropertyChanging("IsSystem", value)) { _IsSystem = value; OnPropertyChanged("IsSystem"); } } } + + private String? _Permission; + /// 权限。对不同资源的权限,逗号分隔,每个资源的权限子项竖线分隔 + [DisplayName("权限")] + [Description("权限。对不同资源的权限,逗号分隔,每个资源的权限子项竖线分隔")] + [DataObjectField(false, false, true, -1)] + [BindColumn("Permission", "权限。对不同资源的权限,逗号分隔,每个资源的权限子项竖线分隔", "")] + public String? Permission { get => _Permission; set { if (OnPropertyChanging("Permission", value)) { _Permission = value; OnPropertyChanged("Permission"); } } } + + private Int32 _Sort; + /// 排序 + [DisplayName("排序")] + [Description("排序")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Sort", "排序", "")] + public Int32 Sort { get => _Sort; set { if (OnPropertyChanging("Sort", value)) { _Sort = value; OnPropertyChanged("Sort"); } } } + + private Int32 _Ex1; + /// 扩展1 + [Category("扩展")] + [DisplayName("扩展1")] + [Description("扩展1")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex1", "扩展1", "")] + public Int32 Ex1 { get => _Ex1; set { if (OnPropertyChanging("Ex1", value)) { _Ex1 = value; OnPropertyChanged("Ex1"); } } } + + private Int32 _Ex2; + /// 扩展2 + [Category("扩展")] + [DisplayName("扩展2")] + [Description("扩展2")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex2", "扩展2", "")] + public Int32 Ex2 { get => _Ex2; set { if (OnPropertyChanging("Ex2", value)) { _Ex2 = value; OnPropertyChanged("Ex2"); } } } + + private Double _Ex3; + /// 扩展3 + [Category("扩展")] + [DisplayName("扩展3")] + [Description("扩展3")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex3", "扩展3", "")] + public Double Ex3 { get => _Ex3; set { if (OnPropertyChanging("Ex3", value)) { _Ex3 = value; OnPropertyChanged("Ex3"); } } } + + private String? _Ex4; + /// 扩展4 + [Category("扩展")] + [DisplayName("扩展4")] + [Description("扩展4")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex4", "扩展4", "")] + public String? Ex4 { get => _Ex4; set { if (OnPropertyChanging("Ex4", value)) { _Ex4 = value; OnPropertyChanged("Ex4"); } } } + + private String? _Ex5; + /// 扩展5 + [Category("扩展")] + [DisplayName("扩展5")] + [Description("扩展5")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex5", "扩展5", "")] + public String? Ex5 { get => _Ex5; set { if (OnPropertyChanging("Ex5", value)) { _Ex5 = value; OnPropertyChanged("Ex5"); } } } + + private String? _Ex6; + /// 扩展6 + [Category("扩展")] + [DisplayName("扩展6")] + [Description("扩展6")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex6", "扩展6", "")] + public String? Ex6 { get => _Ex6; set { if (OnPropertyChanging("Ex6", value)) { _Ex6 = value; OnPropertyChanged("Ex6"); } } } + + private String? _CreateUser; + /// 创建者 + [Category("扩展")] + [DisplayName("创建者")] + [Description("创建者")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateUser", "创建者", "")] + public String? CreateUser { get => _CreateUser; set { if (OnPropertyChanging("CreateUser", value)) { _CreateUser = value; OnPropertyChanged("CreateUser"); } } } + + private Int32 _CreateUserID; + /// 创建用户 + [Category("扩展")] + [DisplayName("创建用户")] + [Description("创建用户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateUserID", "创建用户", "")] + public Int32 CreateUserID { get => _CreateUserID; set { if (OnPropertyChanging("CreateUserID", value)) { _CreateUserID = value; OnPropertyChanged("CreateUserID"); } } } + + private String? _CreateIP; + /// 创建地址 + [Category("扩展")] + [DisplayName("创建地址")] + [Description("创建地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateIP", "创建地址", "")] + public String? CreateIP { get => _CreateIP; set { if (OnPropertyChanging("CreateIP", value)) { _CreateIP = value; OnPropertyChanged("CreateIP"); } } } + + private DateTime _CreateTime; + /// 创建时间 + [Category("扩展")] + [DisplayName("创建时间")] + [Description("创建时间")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateTime", "创建时间", "")] + public DateTime CreateTime { get => _CreateTime; set { if (OnPropertyChanging("CreateTime", value)) { _CreateTime = value; OnPropertyChanged("CreateTime"); } } } + + private String? _UpdateUser; + /// 更新者 + [Category("扩展")] + [DisplayName("更新者")] + [Description("更新者")] + [DataObjectField(false, false, true, 50)] + [BindColumn("UpdateUser", "更新者", "")] + public String? UpdateUser { get => _UpdateUser; set { if (OnPropertyChanging("UpdateUser", value)) { _UpdateUser = value; OnPropertyChanged("UpdateUser"); } } } + + private Int32 _UpdateUserID; + /// 更新用户 + [Category("扩展")] + [DisplayName("更新用户")] + [Description("更新用户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("UpdateUserID", "更新用户", "")] + public Int32 UpdateUserID { get => _UpdateUserID; set { if (OnPropertyChanging("UpdateUserID", value)) { _UpdateUserID = value; OnPropertyChanged("UpdateUserID"); } } } + + private String? _UpdateIP; + /// 更新地址 + [Category("扩展")] + [DisplayName("更新地址")] + [Description("更新地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("UpdateIP", "更新地址", "")] + public String? UpdateIP { get => _UpdateIP; set { if (OnPropertyChanging("UpdateIP", value)) { _UpdateIP = value; OnPropertyChanged("UpdateIP"); } } } + + private DateTime _UpdateTime; + /// 更新时间 + [Category("扩展")] + [DisplayName("更新时间")] + [Description("更新时间")] + [DataObjectField(false, false, false, 0)] + [BindColumn("UpdateTime", "更新时间", "")] + public DateTime UpdateTime { get => _UpdateTime; set { if (OnPropertyChanging("UpdateTime", value)) { _UpdateTime = value; OnPropertyChanged("UpdateTime"); } } } + + private String? _Remark; + /// 备注 + [Category("扩展")] + [DisplayName("备注")] + [Description("备注")] + [DataObjectField(false, false, true, 500)] + [BindColumn("Remark", "备注", "")] + public String? Remark { get => _Remark; set { if (OnPropertyChanging("Remark", value)) { _Remark = value; OnPropertyChanged("Remark"); } } } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IRole model) + { + ID = model.ID; + Name = model.Name; + Enable = model.Enable; + IsSystem = model.IsSystem; + Permission = model.Permission; + Sort = model.Sort; + Ex1 = model.Ex1; + Ex2 = model.Ex2; + Ex3 = model.Ex3; + Ex4 = model.Ex4; + Ex5 = model.Ex5; + Ex6 = model.Ex6; + CreateUser = model.CreateUser; + CreateUserID = model.CreateUserID; + CreateIP = model.CreateIP; + CreateTime = model.CreateTime; + UpdateUser = model.UpdateUser; + UpdateUserID = model.UpdateUserID; + UpdateIP = model.UpdateIP; + UpdateTime = model.UpdateTime; + Remark = model.Remark; + } + #endregion + + #region 获取/设置 字段值 + /// 获取/设置 字段值 + /// 字段名 + /// + public override Object? this[String name] + { + get => name switch + { + "ID" => _ID, + "Name" => _Name, + "Enable" => _Enable, + "IsSystem" => _IsSystem, + "Permission" => _Permission, + "Sort" => _Sort, + "Ex1" => _Ex1, + "Ex2" => _Ex2, + "Ex3" => _Ex3, + "Ex4" => _Ex4, + "Ex5" => _Ex5, + "Ex6" => _Ex6, + "CreateUser" => _CreateUser, + "CreateUserID" => _CreateUserID, + "CreateIP" => _CreateIP, + "CreateTime" => _CreateTime, + "UpdateUser" => _UpdateUser, + "UpdateUserID" => _UpdateUserID, + "UpdateIP" => _UpdateIP, + "UpdateTime" => _UpdateTime, + "Remark" => _Remark, + _ => base[name] + }; + set + { + switch (name) + { + case "ID": _ID = value.ToInt(); break; + case "Name": _Name = Convert.ToString(value); break; + case "Enable": _Enable = value.ToBoolean(); break; + case "IsSystem": _IsSystem = value.ToBoolean(); break; + case "Permission": _Permission = Convert.ToString(value); break; + case "Sort": _Sort = value.ToInt(); break; + case "Ex1": _Ex1 = value.ToInt(); break; + case "Ex2": _Ex2 = value.ToInt(); break; + case "Ex3": _Ex3 = value.ToDouble(); break; + case "Ex4": _Ex4 = Convert.ToString(value); break; + case "Ex5": _Ex5 = Convert.ToString(value); break; + case "Ex6": _Ex6 = Convert.ToString(value); break; + case "CreateUser": _CreateUser = Convert.ToString(value); break; + case "CreateUserID": _CreateUserID = value.ToInt(); break; + case "CreateIP": _CreateIP = Convert.ToString(value); break; + case "CreateTime": _CreateTime = value.ToDateTime(); break; + case "UpdateUser": _UpdateUser = Convert.ToString(value); break; + case "UpdateUserID": _UpdateUserID = value.ToInt(); break; + case "UpdateIP": _UpdateIP = Convert.ToString(value); break; + case "UpdateTime": _UpdateTime = value.ToDateTime(); break; + case "Remark": _Remark = Convert.ToString(value); break; + default: base[name] = value; break; + } + } + } + #endregion + + #region 关联映射 + #endregion + + #region 扩展查询 + /// 根据编号查找 + /// 编号 + /// 实体对象 + public static Role FindByID(Int32 id) + { + if (id < 0) return null; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.ID == id); + + // 单对象缓存 + return Meta.SingleCache[id]; + + //return Find(_.ID == id); + } + + /// 根据名称查找 + /// 名称 + /// 实体对象 + public static Role FindByName(String name) + { + if (name.IsNullOrEmpty()) return null; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.Name.EqualIgnoreCase(name)); + + // 单对象缓存 + return Meta.SingleCache.GetItemWithSlaveKey(name) as Role; + + //return Find(_.Name == name); + } + #endregion + + #region 字段名 + /// 取得角色字段信息的快捷方式 + public partial class _ + { + /// 编号 + public static readonly Field ID = FindByName("ID"); + + /// 名称 + public static readonly Field Name = FindByName("Name"); + + /// 启用 + public static readonly Field Enable = FindByName("Enable"); + + /// 系统。用于业务系统开发使用,不受数据权限约束,禁止修改名称或删除 + public static readonly Field IsSystem = FindByName("IsSystem"); + + /// 权限。对不同资源的权限,逗号分隔,每个资源的权限子项竖线分隔 + public static readonly Field Permission = FindByName("Permission"); + + /// 排序 + public static readonly Field Sort = FindByName("Sort"); + + /// 扩展1 + public static readonly Field Ex1 = FindByName("Ex1"); + + /// 扩展2 + public static readonly Field Ex2 = FindByName("Ex2"); + + /// 扩展3 + public static readonly Field Ex3 = FindByName("Ex3"); + + /// 扩展4 + public static readonly Field Ex4 = FindByName("Ex4"); + + /// 扩展5 + public static readonly Field Ex5 = FindByName("Ex5"); + + /// 扩展6 + public static readonly Field Ex6 = FindByName("Ex6"); + + /// 创建者 + public static readonly Field CreateUser = FindByName("CreateUser"); + + /// 创建用户 + public static readonly Field CreateUserID = FindByName("CreateUserID"); + + /// 创建地址 + public static readonly Field CreateIP = FindByName("CreateIP"); + + /// 创建时间 + public static readonly Field CreateTime = FindByName("CreateTime"); + + /// 更新者 + public static readonly Field UpdateUser = FindByName("UpdateUser"); + + /// 更新用户 + public static readonly Field UpdateUserID = FindByName("UpdateUserID"); + + /// 更新地址 + public static readonly Field UpdateIP = FindByName("UpdateIP"); + + /// 更新时间 + public static readonly Field UpdateTime = FindByName("UpdateTime"); + + /// 备注 + public static readonly Field Remark = FindByName("Remark"); + + static Field FindByName(String name) => Meta.Table.FindByName(name); + } + + /// 取得角色字段名称的快捷方式 + public partial class __ + { + /// 编号 + public const String ID = "ID"; + + /// 名称 + public const String Name = "Name"; + + /// 启用 + public const String Enable = "Enable"; + + /// 系统。用于业务系统开发使用,不受数据权限约束,禁止修改名称或删除 + public const String IsSystem = "IsSystem"; + + /// 权限。对不同资源的权限,逗号分隔,每个资源的权限子项竖线分隔 + public const String Permission = "Permission"; + + /// 排序 + public const String Sort = "Sort"; + + /// 扩展1 + public const String Ex1 = "Ex1"; + + /// 扩展2 + public const String Ex2 = "Ex2"; + + /// 扩展3 + public const String Ex3 = "Ex3"; + + /// 扩展4 + public const String Ex4 = "Ex4"; + + /// 扩展5 + public const String Ex5 = "Ex5"; + + /// 扩展6 + public const String Ex6 = "Ex6"; + + /// 创建者 + public const String CreateUser = "CreateUser"; + + /// 创建用户 + public const String CreateUserID = "CreateUserID"; + + /// 创建地址 + public const String CreateIP = "CreateIP"; + + /// 创建时间 + public const String CreateTime = "CreateTime"; + + /// 更新者 + public const String UpdateUser = "UpdateUser"; + + /// 更新用户 + public const String UpdateUserID = "UpdateUserID"; + + /// 更新地址 + public const String UpdateIP = "UpdateIP"; + + /// 更新时间 + public const String UpdateTime = "UpdateTime"; + + /// 备注 + public const String Remark = "Remark"; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/部门.Biz.cs b/XUnitTest.XCode/Code/Entity/部门.Biz.cs new file mode 100644 index 000000000..dbc33601d --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/部门.Biz.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using NewLife.Log; +using NewLife.Model; +using NewLife.Reflection; +using NewLife.Threading; +using NewLife.Web; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; +using XCode.Membership; +using XCode.Shards; + +namespace XCode.Membership666; + +public partial class Department : Entity +{ + #region 对象操作 + static Department() + { + // 累加字段,生成 Update xx Set Count=Count+1234 Where xxx + //var df = Meta.Factory.AdditionalFields; + //df.Add(nameof(TenantId)); + + // 过滤器 UserModule、TimeModule、IPModule + Meta.Modules.Add(new UserModule { AllowEmpty = false }); + Meta.Modules.Add(); + Meta.Modules.Add(new IPModule { AllowEmpty = false }); + Meta.Modules.Add(); + + // 实体缓存 + // var ec = Meta.Cache; + // ec.Expire = 60; + } + + /// 验证并修补数据,返回验证结果,或者通过抛出异常的方式提示验证失败。 + /// 添删改方法 + public override Boolean Valid(DataMethod method) + { + //if (method == DataMethod.Delete) return true; + // 如果没有脏数据,则不需要进行任何处理 + if (!HasDirty) return true; + + // 这里验证参数范围,建议抛出参数异常,指定参数名,前端用户界面可以捕获参数异常并聚焦到对应的参数输入框 + if (Name.IsNullOrEmpty()) throw new ArgumentNullException(nameof(Name), "名称不能为空!"); + + // 建议先调用基类方法,基类方法会做一些统一处理 + if (!base.Valid(method)) return false; + + // 在新插入数据或者修改了指定字段时进行修正 + + // 保留2位小数 + //Ex3 = Math.Round(Ex3, 2); + + // 处理当前已登录用户信息,可以由UserModule过滤器代劳 + /*var user = ManageProvider.User; + if (user != null) + { + if (method == DataMethod.Insert && !Dirtys[nameof(CreateUserID)]) CreateUserID = user.ID; + if (!Dirtys[nameof(UpdateUserID)]) UpdateUserID = user.ID; + }*/ + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateTime)]) CreateTime = DateTime.Now; + //if (!Dirtys[nameof(UpdateTime)]) UpdateTime = DateTime.Now; + //if (method == DataMethod.Insert && !Dirtys[nameof(CreateIP)]) CreateIP = ManageProvider.UserHost; + //if (!Dirtys[nameof(UpdateIP)]) UpdateIP = ManageProvider.UserHost; + + return true; + } + + ///// 首次连接数据库时初始化数据,仅用于实体类重载,用户不应该调用该方法 + //[EditorBrowsable(EditorBrowsableState.Never)] + //protected override void InitData() + //{ + // // InitData一般用于当数据表没有数据时添加一些默认数据,该实体类的任何第一次数据库操作都会触发该方法,默认异步调用 + // if (Meta.Session.Count > 0) return; + + // if (XTrace.Debug) XTrace.WriteLine("开始初始化Department[部门]数据……"); + + // var entity = new Department(); + // entity.TenantId = 0; + // entity.Code = "abc"; + // entity.Name = "abc"; + // entity.FullName = "abc"; + // entity.ParentID = 0; + // entity.Level = 0; + // entity.Sort = 0; + // entity.Enable = true; + // entity.Visible = true; + // entity.ManagerId = 0; + // entity.Ex1 = 0; + // entity.Ex2 = 0; + // entity.Ex3 = 0.0; + // entity.Ex4 = "abc"; + // entity.Ex5 = "abc"; + // entity.Ex6 = "abc"; + // entity.Insert(); + + // if (XTrace.Debug) XTrace.WriteLine("完成初始化Department[部门]数据!"); + //} + + ///// 已重载。基类先调用Valid(true)验证数据,然后在事务保护内调用OnInsert + ///// + //public override Int32 Insert() + //{ + // return base.Insert(); + //} + + ///// 已重载。在事务保护范围内处理业务,位于Valid之后 + ///// + //protected override Int32 OnDelete() + //{ + // return base.OnDelete(); + //} + #endregion + + #region 扩展属性 + #endregion + + #region 高级查询 + /// 高级查询 + /// 租户 + /// 代码 + /// 名称 + /// 父级 + /// 更新时间开始 + /// 更新时间结束 + /// 关键字 + /// 分页参数信息。可携带统计和数据权限扩展查询等信息 + /// 实体列表 + public static IList Search(Int32 tenantId, String code, String name, Int32 parentId, DateTime start, DateTime end, String key, PageParameter page) + { + var exp = new WhereExpression(); + + if (tenantId >= 0) exp &= _.TenantId == tenantId; + if (!code.IsNullOrEmpty()) exp &= _.Code == code; + if (!name.IsNullOrEmpty()) exp &= _.Name == name; + if (parentId >= 0) exp &= _.ParentID == parentId; + exp &= _.UpdateTime.Between(start, end); + if (!key.IsNullOrEmpty()) exp &= _.Code.Contains(key) | _.Name.Contains(key) | _.FullName.Contains(key) | _.Ex4.Contains(key) | _.Ex5.Contains(key) | _.Ex6.Contains(key) | _.CreateUser.Contains(key) | _.CreateIP.Contains(key) | _.UpdateUser.Contains(key) | _.UpdateIP.Contains(key) | _.Remark.Contains(key); + + return FindAll(exp, page); + } + + // Select Count(ID) as ID,Code From Department Where CreateTime>'2020-01-24 00:00:00' Group By Code Order By ID Desc limit 20 + static readonly FieldCache _CodeCache = new FieldCache(nameof(Code)) + { + //Where = _.CreateTime > DateTime.Today.AddDays(-30) & Expression.Empty + }; + + /// 获取代码列表,字段缓存10分钟,分组统计数据最多的前20种,用于魔方前台下拉选择 + /// + public static IDictionary GetCodeList() => _CodeCache.FindAllName(); + #endregion + + #region 业务操作 + public IDepartment ToModel() + { + var model = new Department(); + model.Copy(this); + + return model; + } + + #endregion +} diff --git a/XUnitTest.XCode/Code/Entity/部门.cs b/XUnitTest.XCode/Code/Entity/部门.cs new file mode 100644 index 000000000..da470bd87 --- /dev/null +++ b/XUnitTest.XCode/Code/Entity/部门.cs @@ -0,0 +1,617 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; +using NewLife; +using NewLife.Data; +using XCode; +using XCode.Cache; +using XCode.Configuration; +using XCode.DataAccessLayer; + +namespace XCode.Membership666; + +/// 部门。组织机构,多级树状结构 +[Serializable] +[DataObject] +[Description("部门。组织机构,多级树状结构")] +[BindIndex("IX_Department_Name", false, "Name")] +[BindIndex("IX_Department_ParentID_Name", false, "ParentID,Name")] +[BindIndex("IX_Department_Code", false, "Code")] +[BindIndex("IX_Department_UpdateTime", false, "UpdateTime")] +[BindIndex("IX_Department_TenantId", false, "TenantId")] +[BindTable("Department", Description = "部门。组织机构,多级树状结构", ConnName = "Membership", DbType = DatabaseType.None)] +public partial class Department : IDepartment, IEntity +{ + #region 属性 + private Int32 _ID; + /// 编号 + [DisplayName("编号")] + [Description("编号")] + [DataObjectField(true, true, false, 0)] + [BindColumn("ID", "编号", "")] + public Int32 ID { get => _ID; set { if (OnPropertyChanging("ID", value)) { _ID = value; OnPropertyChanged("ID"); } } } + + private Int32 _TenantId; + /// 租户 + [DisplayName("租户")] + [Description("租户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("TenantId", "租户", "")] + public Int32 TenantId { get => _TenantId; set { if (OnPropertyChanging("TenantId", value)) { _TenantId = value; OnPropertyChanged("TenantId"); } } } + + private String? _Code; + /// 代码 + [DisplayName("代码")] + [Description("代码")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Code", "代码", "")] + public String? Code { get => _Code; set { if (OnPropertyChanging("Code", value)) { _Code = value; OnPropertyChanged("Code"); } } } + + private String _Name = null!; + /// 名称 + [DisplayName("名称")] + [Description("名称")] + [DataObjectField(false, false, false, 50)] + [BindColumn("Name", "名称", "", Master = true)] + public String Name { get => _Name; set { if (OnPropertyChanging("Name", value)) { _Name = value; OnPropertyChanged("Name"); } } } + + private String? _FullName; + /// 全名 + [DisplayName("全名")] + [Description("全名")] + [DataObjectField(false, false, true, 200)] + [BindColumn("FullName", "全名", "")] + public String? FullName { get => _FullName; set { if (OnPropertyChanging("FullName", value)) { _FullName = value; OnPropertyChanged("FullName"); } } } + + private Int32 _ParentID; + /// 父级 + [DisplayName("父级")] + [Description("父级")] + [DataObjectField(false, false, false, 0)] + [BindColumn("ParentID", "父级", "")] + public Int32 ParentID { get => _ParentID; set { if (OnPropertyChanging("ParentID", value)) { _ParentID = value; OnPropertyChanged("ParentID"); } } } + + private Int32 _Level; + /// 层级。树状结构的层级 + [DisplayName("层级")] + [Description("层级。树状结构的层级")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Level", "层级。树状结构的层级", "")] + public Int32 Level { get => _Level; set { if (OnPropertyChanging("Level", value)) { _Level = value; OnPropertyChanged("Level"); } } } + + private Int32 _Sort; + /// 排序。同级内排序 + [DisplayName("排序")] + [Description("排序。同级内排序")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Sort", "排序。同级内排序", "")] + public Int32 Sort { get => _Sort; set { if (OnPropertyChanging("Sort", value)) { _Sort = value; OnPropertyChanged("Sort"); } } } + + private Boolean _Enable; + /// 启用 + [DisplayName("启用")] + [Description("启用")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Enable", "启用", "")] + public Boolean Enable { get => _Enable; set { if (OnPropertyChanging("Enable", value)) { _Enable = value; OnPropertyChanged("Enable"); } } } + + private Boolean _Visible; + /// 可见 + [DisplayName("可见")] + [Description("可见")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Visible", "可见", "")] + public Boolean Visible { get => _Visible; set { if (OnPropertyChanging("Visible", value)) { _Visible = value; OnPropertyChanged("Visible"); } } } + + private Int32 _ManagerId; + /// 管理者 + [DisplayName("管理者")] + [Description("管理者")] + [DataObjectField(false, false, false, 0)] + [BindColumn("ManagerId", "管理者", "")] + public Int32 ManagerId { get => _ManagerId; set { if (OnPropertyChanging("ManagerId", value)) { _ManagerId = value; OnPropertyChanged("ManagerId"); } } } + + private Int32 _Ex1; + /// 扩展1 + [Category("扩展")] + [DisplayName("扩展1")] + [Description("扩展1")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex1", "扩展1", "")] + public Int32 Ex1 { get => _Ex1; set { if (OnPropertyChanging("Ex1", value)) { _Ex1 = value; OnPropertyChanged("Ex1"); } } } + + private Int32 _Ex2; + /// 扩展2 + [Category("扩展")] + [DisplayName("扩展2")] + [Description("扩展2")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex2", "扩展2", "")] + public Int32 Ex2 { get => _Ex2; set { if (OnPropertyChanging("Ex2", value)) { _Ex2 = value; OnPropertyChanged("Ex2"); } } } + + private Double _Ex3; + /// 扩展3 + [Category("扩展")] + [DisplayName("扩展3")] + [Description("扩展3")] + [DataObjectField(false, false, false, 0)] + [BindColumn("Ex3", "扩展3", "")] + public Double Ex3 { get => _Ex3; set { if (OnPropertyChanging("Ex3", value)) { _Ex3 = value; OnPropertyChanged("Ex3"); } } } + + private String? _Ex4; + /// 扩展4 + [Category("扩展")] + [DisplayName("扩展4")] + [Description("扩展4")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex4", "扩展4", "")] + public String? Ex4 { get => _Ex4; set { if (OnPropertyChanging("Ex4", value)) { _Ex4 = value; OnPropertyChanged("Ex4"); } } } + + private String? _Ex5; + /// 扩展5 + [Category("扩展")] + [DisplayName("扩展5")] + [Description("扩展5")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex5", "扩展5", "")] + public String? Ex5 { get => _Ex5; set { if (OnPropertyChanging("Ex5", value)) { _Ex5 = value; OnPropertyChanged("Ex5"); } } } + + private String? _Ex6; + /// 扩展6 + [Category("扩展")] + [DisplayName("扩展6")] + [Description("扩展6")] + [DataObjectField(false, false, true, 50)] + [BindColumn("Ex6", "扩展6", "")] + public String? Ex6 { get => _Ex6; set { if (OnPropertyChanging("Ex6", value)) { _Ex6 = value; OnPropertyChanged("Ex6"); } } } + + private String? _CreateUser; + /// 创建者 + [Category("扩展")] + [DisplayName("创建者")] + [Description("创建者")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateUser", "创建者", "")] + public String? CreateUser { get => _CreateUser; set { if (OnPropertyChanging("CreateUser", value)) { _CreateUser = value; OnPropertyChanged("CreateUser"); } } } + + private Int32 _CreateUserID; + /// 创建用户 + [Category("扩展")] + [DisplayName("创建用户")] + [Description("创建用户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateUserID", "创建用户", "")] + public Int32 CreateUserID { get => _CreateUserID; set { if (OnPropertyChanging("CreateUserID", value)) { _CreateUserID = value; OnPropertyChanged("CreateUserID"); } } } + + private String? _CreateIP; + /// 创建地址 + [Category("扩展")] + [DisplayName("创建地址")] + [Description("创建地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("CreateIP", "创建地址", "")] + public String? CreateIP { get => _CreateIP; set { if (OnPropertyChanging("CreateIP", value)) { _CreateIP = value; OnPropertyChanged("CreateIP"); } } } + + private DateTime _CreateTime; + /// 创建时间 + [Category("扩展")] + [DisplayName("创建时间")] + [Description("创建时间")] + [DataObjectField(false, false, false, 0)] + [BindColumn("CreateTime", "创建时间", "")] + public DateTime CreateTime { get => _CreateTime; set { if (OnPropertyChanging("CreateTime", value)) { _CreateTime = value; OnPropertyChanged("CreateTime"); } } } + + private String? _UpdateUser; + /// 更新者 + [Category("扩展")] + [DisplayName("更新者")] + [Description("更新者")] + [DataObjectField(false, false, true, 50)] + [BindColumn("UpdateUser", "更新者", "")] + public String? UpdateUser { get => _UpdateUser; set { if (OnPropertyChanging("UpdateUser", value)) { _UpdateUser = value; OnPropertyChanged("UpdateUser"); } } } + + private Int32 _UpdateUserID; + /// 更新用户 + [Category("扩展")] + [DisplayName("更新用户")] + [Description("更新用户")] + [DataObjectField(false, false, false, 0)] + [BindColumn("UpdateUserID", "更新用户", "")] + public Int32 UpdateUserID { get => _UpdateUserID; set { if (OnPropertyChanging("UpdateUserID", value)) { _UpdateUserID = value; OnPropertyChanged("UpdateUserID"); } } } + + private String? _UpdateIP; + /// 更新地址 + [Category("扩展")] + [DisplayName("更新地址")] + [Description("更新地址")] + [DataObjectField(false, false, true, 50)] + [BindColumn("UpdateIP", "更新地址", "")] + public String? UpdateIP { get => _UpdateIP; set { if (OnPropertyChanging("UpdateIP", value)) { _UpdateIP = value; OnPropertyChanged("UpdateIP"); } } } + + private DateTime _UpdateTime; + /// 更新时间 + [Category("扩展")] + [DisplayName("更新时间")] + [Description("更新时间")] + [DataObjectField(false, false, false, 0)] + [BindColumn("UpdateTime", "更新时间", "")] + public DateTime UpdateTime { get => _UpdateTime; set { if (OnPropertyChanging("UpdateTime", value)) { _UpdateTime = value; OnPropertyChanged("UpdateTime"); } } } + + private String? _Remark; + /// 备注 + [Category("扩展")] + [DisplayName("备注")] + [Description("备注")] + [DataObjectField(false, false, true, 500)] + [BindColumn("Remark", "备注", "")] + public String? Remark { get => _Remark; set { if (OnPropertyChanging("Remark", value)) { _Remark = value; OnPropertyChanged("Remark"); } } } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IDepartment model) + { + ID = model.ID; + TenantId = model.TenantId; + Code = model.Code; + Name = model.Name; + FullName = model.FullName; + ParentID = model.ParentID; + Level = model.Level; + Sort = model.Sort; + Enable = model.Enable; + Visible = model.Visible; + ManagerId = model.ManagerId; + Ex1 = model.Ex1; + Ex2 = model.Ex2; + Ex3 = model.Ex3; + Ex4 = model.Ex4; + Ex5 = model.Ex5; + Ex6 = model.Ex6; + CreateUser = model.CreateUser; + CreateUserID = model.CreateUserID; + CreateIP = model.CreateIP; + CreateTime = model.CreateTime; + UpdateUser = model.UpdateUser; + UpdateUserID = model.UpdateUserID; + UpdateIP = model.UpdateIP; + UpdateTime = model.UpdateTime; + Remark = model.Remark; + } + #endregion + + #region 获取/设置 字段值 + /// 获取/设置 字段值 + /// 字段名 + /// + public override Object? this[String name] + { + get => name switch + { + "ID" => _ID, + "TenantId" => _TenantId, + "Code" => _Code, + "Name" => _Name, + "FullName" => _FullName, + "ParentID" => _ParentID, + "Level" => _Level, + "Sort" => _Sort, + "Enable" => _Enable, + "Visible" => _Visible, + "ManagerId" => _ManagerId, + "Ex1" => _Ex1, + "Ex2" => _Ex2, + "Ex3" => _Ex3, + "Ex4" => _Ex4, + "Ex5" => _Ex5, + "Ex6" => _Ex6, + "CreateUser" => _CreateUser, + "CreateUserID" => _CreateUserID, + "CreateIP" => _CreateIP, + "CreateTime" => _CreateTime, + "UpdateUser" => _UpdateUser, + "UpdateUserID" => _UpdateUserID, + "UpdateIP" => _UpdateIP, + "UpdateTime" => _UpdateTime, + "Remark" => _Remark, + _ => base[name] + }; + set + { + switch (name) + { + case "ID": _ID = value.ToInt(); break; + case "TenantId": _TenantId = value.ToInt(); break; + case "Code": _Code = Convert.ToString(value); break; + case "Name": _Name = Convert.ToString(value); break; + case "FullName": _FullName = Convert.ToString(value); break; + case "ParentID": _ParentID = value.ToInt(); break; + case "Level": _Level = value.ToInt(); break; + case "Sort": _Sort = value.ToInt(); break; + case "Enable": _Enable = value.ToBoolean(); break; + case "Visible": _Visible = value.ToBoolean(); break; + case "ManagerId": _ManagerId = value.ToInt(); break; + case "Ex1": _Ex1 = value.ToInt(); break; + case "Ex2": _Ex2 = value.ToInt(); break; + case "Ex3": _Ex3 = value.ToDouble(); break; + case "Ex4": _Ex4 = Convert.ToString(value); break; + case "Ex5": _Ex5 = Convert.ToString(value); break; + case "Ex6": _Ex6 = Convert.ToString(value); break; + case "CreateUser": _CreateUser = Convert.ToString(value); break; + case "CreateUserID": _CreateUserID = value.ToInt(); break; + case "CreateIP": _CreateIP = Convert.ToString(value); break; + case "CreateTime": _CreateTime = value.ToDateTime(); break; + case "UpdateUser": _UpdateUser = Convert.ToString(value); break; + case "UpdateUserID": _UpdateUserID = value.ToInt(); break; + case "UpdateIP": _UpdateIP = Convert.ToString(value); break; + case "UpdateTime": _UpdateTime = value.ToDateTime(); break; + case "Remark": _Remark = Convert.ToString(value); break; + default: base[name] = value; break; + } + } + } + #endregion + + #region 关联映射 + /// 租户 + [XmlIgnore, IgnoreDataMember, ScriptIgnore] + public Tenant? Tenant => Extends.Get(nameof(Tenant), k => Tenant.FindById(TenantId)); + + /// 租户 + [Map(nameof(TenantId), typeof(Tenant), "Id")] + public String? TenantName => Tenant?.ToString(); + + /// 管理者 + [XmlIgnore, IgnoreDataMember, ScriptIgnore] + public User? Manager => Extends.Get(nameof(Manager), k => User.FindByID(ManagerId)); + + /// 管理者 + [Map(nameof(ManagerId), typeof(User), "ID")] + public String? ManagerName => Manager?.ToString(); + + #endregion + + #region 扩展查询 + /// 根据编号查找 + /// 编号 + /// 实体对象 + public static Department FindByID(Int32 id) + { + if (id < 0) return null; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.Find(e => e.ID == id); + + // 单对象缓存 + return Meta.SingleCache[id]; + + //return Find(_.ID == id); + } + + /// 根据名称查找 + /// 名称 + /// 实体列表 + public static IList FindAllByName(String name) + { + if (name.IsNullOrEmpty()) return []; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.Name.EqualIgnoreCase(name)); + + return FindAll(_.Name == name); + } + + /// 根据父级、名称查找 + /// 父级 + /// 名称 + /// 实体列表 + public static IList FindAllByParentIDAndName(Int32 parentId, String name) + { + if (parentId < 0) return []; + if (name.IsNullOrEmpty()) return []; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.ParentID == parentId && e.Name.EqualIgnoreCase(name)); + + return FindAll(_.ParentID == parentId & _.Name == name); + } + + /// 根据代码查找 + /// 代码 + /// 实体列表 + public static IList FindAllByCode(String code) + { + if (code.IsNullOrEmpty()) return []; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.Code.EqualIgnoreCase(code)); + + return FindAll(_.Code == code); + } + + /// 根据租户查找 + /// 租户 + /// 实体列表 + public static IList FindAllByTenantId(Int32 tenantId) + { + if (tenantId < 0) return []; + + // 实体缓存 + if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.TenantId == tenantId); + + return FindAll(_.TenantId == tenantId); + } + #endregion + + #region 字段名 + /// 取得部门字段信息的快捷方式 + public partial class _ + { + /// 编号 + public static readonly Field ID = FindByName("ID"); + + /// 租户 + public static readonly Field TenantId = FindByName("TenantId"); + + /// 代码 + public static readonly Field Code = FindByName("Code"); + + /// 名称 + public static readonly Field Name = FindByName("Name"); + + /// 全名 + public static readonly Field FullName = FindByName("FullName"); + + /// 父级 + public static readonly Field ParentID = FindByName("ParentID"); + + /// 层级。树状结构的层级 + public static readonly Field Level = FindByName("Level"); + + /// 排序。同级内排序 + public static readonly Field Sort = FindByName("Sort"); + + /// 启用 + public static readonly Field Enable = FindByName("Enable"); + + /// 可见 + public static readonly Field Visible = FindByName("Visible"); + + /// 管理者 + public static readonly Field ManagerId = FindByName("ManagerId"); + + /// 扩展1 + public static readonly Field Ex1 = FindByName("Ex1"); + + /// 扩展2 + public static readonly Field Ex2 = FindByName("Ex2"); + + /// 扩展3 + public static readonly Field Ex3 = FindByName("Ex3"); + + /// 扩展4 + public static readonly Field Ex4 = FindByName("Ex4"); + + /// 扩展5 + public static readonly Field Ex5 = FindByName("Ex5"); + + /// 扩展6 + public static readonly Field Ex6 = FindByName("Ex6"); + + /// 创建者 + public static readonly Field CreateUser = FindByName("CreateUser"); + + /// 创建用户 + public static readonly Field CreateUserID = FindByName("CreateUserID"); + + /// 创建地址 + public static readonly Field CreateIP = FindByName("CreateIP"); + + /// 创建时间 + public static readonly Field CreateTime = FindByName("CreateTime"); + + /// 更新者 + public static readonly Field UpdateUser = FindByName("UpdateUser"); + + /// 更新用户 + public static readonly Field UpdateUserID = FindByName("UpdateUserID"); + + /// 更新地址 + public static readonly Field UpdateIP = FindByName("UpdateIP"); + + /// 更新时间 + public static readonly Field UpdateTime = FindByName("UpdateTime"); + + /// 备注 + public static readonly Field Remark = FindByName("Remark"); + + static Field FindByName(String name) => Meta.Table.FindByName(name); + } + + /// 取得部门字段名称的快捷方式 + public partial class __ + { + /// 编号 + public const String ID = "ID"; + + /// 租户 + public const String TenantId = "TenantId"; + + /// 代码 + public const String Code = "Code"; + + /// 名称 + public const String Name = "Name"; + + /// 全名 + public const String FullName = "FullName"; + + /// 父级 + public const String ParentID = "ParentID"; + + /// 层级。树状结构的层级 + public const String Level = "Level"; + + /// 排序。同级内排序 + public const String Sort = "Sort"; + + /// 启用 + public const String Enable = "Enable"; + + /// 可见 + public const String Visible = "Visible"; + + /// 管理者 + public const String ManagerId = "ManagerId"; + + /// 扩展1 + public const String Ex1 = "Ex1"; + + /// 扩展2 + public const String Ex2 = "Ex2"; + + /// 扩展3 + public const String Ex3 = "Ex3"; + + /// 扩展4 + public const String Ex4 = "Ex4"; + + /// 扩展5 + public const String Ex5 = "Ex5"; + + /// 扩展6 + public const String Ex6 = "Ex6"; + + /// 创建者 + public const String CreateUser = "CreateUser"; + + /// 创建用户 + public const String CreateUserID = "CreateUserID"; + + /// 创建地址 + public const String CreateIP = "CreateIP"; + + /// 创建时间 + public const String CreateTime = "CreateTime"; + + /// 更新者 + public const String UpdateUser = "UpdateUser"; + + /// 更新用户 + public const String UpdateUserID = "UpdateUserID"; + + /// 更新地址 + public const String UpdateIP = "UpdateIP"; + + /// 更新时间 + public const String UpdateTime = "UpdateTime"; + + /// 备注 + public const String Remark = "Remark"; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityBuilderTests.cs b/XUnitTest.XCode/Code/EntityBuilderTests.cs index 8f30c0368..2a24dca23 100644 --- a/XUnitTest.XCode/Code/EntityBuilderTests.cs +++ b/XUnitTest.XCode/Code/EntityBuilderTests.cs @@ -27,6 +27,7 @@ public class EntityBuilderTests //var file2 = @"..\..\XUnitTest.XCode\".CombinePath(file); //File.WriteAllText(file2, text); + if (!File.Exists(file)) return null; var target = File.ReadAllText(file.GetFullPath()); return target; @@ -298,29 +299,75 @@ public class EntityBuilderTests option.Output = @"Output\EntityInterfaces\"; InterfaceBuilder.BuildInterfaces(tables, option); + // 拷贝输出到原始目录,仅测试使用 + foreach (var table in tables) + { + { + var rs = File.ReadAllText($"Entity\\{table.DisplayName}.cs".GetFullPath()); + var target = ReadTarget($"Code\\Entity\\{table.DisplayName}.cs", rs); + } + { + var rs = File.ReadAllText($"Entity\\{table.DisplayName}.Biz.cs".GetFullPath()); + var target = ReadTarget($"Code\\Entity\\{table.DisplayName}.Biz.cs", rs); + } + { + var rs = File.ReadAllText($"Output\\EntityModels\\{table.Name}Model.cs".GetFullPath()); + var target = ReadTarget($"Code\\EntityModels\\{table.Name}Model.cs", rs); + } + { + var rs = File.ReadAllText($"Output\\EntityInterfaces\\I{table.Name}.cs".GetFullPath()); + var target = ReadTarget($"Code\\EntityInterfaces\\I{table.Name}.cs", rs); + } + } + { var rs = File.ReadAllText("Entity\\日志.cs".GetFullPath()); var target = ReadTarget("Code\\Entity\\日志.cs", rs); Assert.Equal(target, rs); } - { var rs = File.ReadAllText("Entity\\日志.Biz.cs".GetFullPath()); var target = ReadTarget("Code\\Entity\\日志.Biz.cs", rs); Assert.Equal(target, rs); } - { var rs = File.ReadAllText("Output\\EntityModels\\LogModel.cs".GetFullPath()); var target = ReadTarget("Code\\EntityModels\\LogModel.cs", rs); Assert.Equal(target, rs); } - { var rs = File.ReadAllText("Output\\EntityInterfaces\\ILog.cs".GetFullPath()); var target = ReadTarget("Code\\EntityInterfaces\\ILog.cs", rs); Assert.Equal(target, rs); } + + { + var rs = File.ReadAllText("Entity\\用户日志.cs".GetFullPath()); + var target = ReadTarget("Code\\Entity\\用户日志.cs", rs); + Assert.Equal(target, rs); + } + { + var rs = File.ReadAllText("Entity\\用户日志.Biz.cs".GetFullPath()); + var target = ReadTarget("Code\\Entity\\用户日志.Biz.cs", rs); + Assert.Equal(target, rs); + + rs = File.ReadAllText("Output\\EntityInterfaces\\IUserLog.cs".GetFullPath()); + ReadTarget("Code\\EntityInterfaces\\IUserLog.cs", rs); + } + + { + var rs = File.ReadAllText("Entity\\成员日志.cs".GetFullPath()); + var target = ReadTarget("Code\\Entity\\成员日志.cs", rs); + Assert.Equal(target, rs); + } + { + var rs = File.ReadAllText("Entity\\成员日志.Biz.cs".GetFullPath()); + var target = ReadTarget("Code\\Entity\\成员日志.Biz.cs", rs); + Assert.Equal(target, rs); + + rs = File.ReadAllText("Output\\EntityInterfaces\\IMemberLog.cs".GetFullPath()); + ReadTarget("Code\\EntityInterfaces\\IMemberLog.cs", rs); + } } [Fact] diff --git a/XUnitTest.XCode/Code/EntityInterfaces/IArea.cs b/XUnitTest.XCode/Code/EntityInterfaces/IArea.cs new file mode 100644 index 000000000..df6a3a450 --- /dev/null +++ b/XUnitTest.XCode/Code/EntityInterfaces/IArea.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 地区。行政区划数据,最高支持四级地址,9位数字 +public partial interface IArea +{ + #region 属性 + /// 编码。行政区划编码 + Int32 ID { get; set; } + + /// 名称 + String? Name { get; set; } + + /// 全名 + String? FullName { get; set; } + + /// 父级 + Int32 ParentID { get; set; } + + /// 层级 + Int32 Level { get; set; } + + /// 类型。省市县,自治州等 + String? Kind { get; set; } + + /// 英文名 + String? English { get; set; } + + /// 拼音 + String? PinYin { get; set; } + + /// 简拼 + String? JianPin { get; set; } + + /// 区号。电话区号 + String? TelCode { get; set; } + + /// 邮编。邮政编码 + String? ZipCode { get; set; } + + /// 经度 + Double Longitude { get; set; } + + /// 纬度 + Double Latitude { get; set; } + + /// 地址编码。字符串前缀相同越多,地理距离越近,8位精度19米,6位610米 + String? GeoHash { get; set; } + + /// 启用 + Boolean Enable { get; set; } + + /// 创建时间 + DateTime CreateTime { get; set; } + + /// 更新时间 + DateTime UpdateTime { get; set; } + + /// 备注 + String? Remark { get; set; } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityInterfaces/IDepartment.cs b/XUnitTest.XCode/Code/EntityInterfaces/IDepartment.cs new file mode 100644 index 000000000..ecd8b813c --- /dev/null +++ b/XUnitTest.XCode/Code/EntityInterfaces/IDepartment.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 部门。组织机构,多级树状结构 +public partial interface IDepartment +{ + #region 属性 + /// 编号 + Int32 ID { get; set; } + + /// 租户 + Int32 TenantId { get; set; } + + /// 代码 + String? Code { get; set; } + + /// 名称 + String Name { get; set; } + + /// 全名 + String? FullName { get; set; } + + /// 父级 + Int32 ParentID { get; set; } + + /// 层级。树状结构的层级 + Int32 Level { get; set; } + + /// 排序。同级内排序 + Int32 Sort { get; set; } + + /// 启用 + Boolean Enable { get; set; } + + /// 可见 + Boolean Visible { get; set; } + + /// 管理者 + Int32 ManagerId { get; set; } + + /// 扩展1 + Int32 Ex1 { get; set; } + + /// 扩展2 + Int32 Ex2 { get; set; } + + /// 扩展3 + Double Ex3 { get; set; } + + /// 扩展4 + String? Ex4 { get; set; } + + /// 扩展5 + String? Ex5 { get; set; } + + /// 扩展6 + String? Ex6 { get; set; } + + /// 创建者 + String? CreateUser { get; set; } + + /// 创建用户 + Int32 CreateUserID { get; set; } + + /// 创建地址 + String? CreateIP { get; set; } + + /// 创建时间 + DateTime CreateTime { get; set; } + + /// 更新者 + String? UpdateUser { get; set; } + + /// 更新用户 + Int32 UpdateUserID { get; set; } + + /// 更新地址 + String? UpdateIP { get; set; } + + /// 更新时间 + DateTime UpdateTime { get; set; } + + /// 备注 + String? Remark { get; set; } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityInterfaces/ILog.cs b/XUnitTest.XCode/Code/EntityInterfaces/ILog.cs index 1aec6b0cd..9305e18d9 100644 --- a/XUnitTest.XCode/Code/EntityInterfaces/ILog.cs +++ b/XUnitTest.XCode/Code/EntityInterfaces/ILog.cs @@ -5,13 +5,13 @@ using System.Runtime.Serialization; using System.Web.Script.Serialization; using System.Xml.Serialization; -namespace XCode.Membership; +namespace XCode.Membership666; /// 日志 public partial interface ILog { #region 属性 - /// 编号 + /// 编号。按天分表 Int64 ID { get; set; } /// 类别 diff --git a/XUnitTest.XCode/Code/EntityInterfaces/IMemberLog.cs b/XUnitTest.XCode/Code/EntityInterfaces/IMemberLog.cs new file mode 100644 index 000000000..dfa756a3f --- /dev/null +++ b/XUnitTest.XCode/Code/EntityInterfaces/IMemberLog.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 成员日志 +public partial interface IMemberLog +{ + #region 属性 + /// 编号 + Int64 ID { get; set; } + + /// 数据分区 + String? Ds { get; set; } + + /// 类别 + String? Category { get; set; } + + /// 操作 + String? Action { get; set; } + + /// 链接 + Int32 LinkID { get; set; } + + /// 成功 + Boolean Success { get; set; } + + /// 用户名 + String? UserName { get; set; } + + /// 扩展1 + Int32 Ex1 { get; set; } + + /// 扩展2 + Int32 Ex2 { get; set; } + + /// 扩展3 + Double Ex3 { get; set; } + + /// 扩展4 + String? Ex4 { get; set; } + + /// 扩展5 + String? Ex5 { get; set; } + + /// 扩展6 + String? Ex6 { get; set; } + + /// 性能追踪。用于APM性能追踪定位,还原该事件的调用链 + String? TraceId { get; set; } + + /// 创建者 + String? CreateUser { get; set; } + + /// 创建用户 + Int32 CreateUserID { get; set; } + + /// 创建地址 + String? CreateIP { get; set; } + + /// 时间 + DateTime CreateTime { get; set; } + + /// 详细信息 + String? Remark { get; set; } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityInterfaces/IMenu.cs b/XUnitTest.XCode/Code/EntityInterfaces/IMenu.cs new file mode 100644 index 000000000..2cc31574c --- /dev/null +++ b/XUnitTest.XCode/Code/EntityInterfaces/IMenu.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 菜单 +public partial interface IMenu +{ + #region 属性 + /// 编号 + Int32 ID { get; set; } + + /// 名称 + String Name { get; set; } + + /// 显示名 + String? DisplayName { get; set; } + + /// 全名 + String? FullName { get; set; } + + /// 父编号 + Int32 ParentID { get; set; } + + /// 链接 + String? Url { get; set; } + + /// 排序 + Int32 Sort { get; set; } + + /// 图标 + String? Icon { get; set; } + + /// 可见 + Boolean Visible { get; set; } + + /// 必要。必要的菜单,必须至少有角色拥有这些权限,如果没有则自动授权给系统角色 + Boolean Necessary { get; set; } + + /// 新窗口。新窗口打开链接 + Boolean NewWindow { get; set; } + + /// 权限子项。逗号分隔,每个权限子项名值竖线分隔 + String? Permission { get; set; } + + /// 扩展1 + Int32 Ex1 { get; set; } + + /// 扩展2 + Int32 Ex2 { get; set; } + + /// 扩展3 + Double Ex3 { get; set; } + + /// 扩展4 + String? Ex4 { get; set; } + + /// 扩展5 + String? Ex5 { get; set; } + + /// 扩展6 + String? Ex6 { get; set; } + + /// 创建者 + String? CreateUser { get; set; } + + /// 创建用户 + Int32 CreateUserID { get; set; } + + /// 创建地址 + String? CreateIP { get; set; } + + /// 创建时间 + DateTime CreateTime { get; set; } + + /// 更新者 + String? UpdateUser { get; set; } + + /// 更新用户 + Int32 UpdateUserID { get; set; } + + /// 更新地址 + String? UpdateIP { get; set; } + + /// 更新时间 + DateTime UpdateTime { get; set; } + + /// 备注 + String? Remark { get; set; } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityInterfaces/IParameter.cs b/XUnitTest.XCode/Code/EntityInterfaces/IParameter.cs new file mode 100644 index 000000000..bd862d25d --- /dev/null +++ b/XUnitTest.XCode/Code/EntityInterfaces/IParameter.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 字典参数 +public partial interface IParameter +{ + #region 属性 + /// 编号 + Int32 ID { get; set; } + + /// 用户。按用户区分参数,用户0表示系统级 + Int32 UserID { get; set; } + + /// 类别 + String? Category { get; set; } + + /// 名称 + String? Name { get; set; } + + /// 数值 + String? Value { get; set; } + + /// 长数值 + String? LongValue { get; set; } + + /// 种类。0普通,21列表,22名值 + XCode.Membership.ParameterKinds Kind { get; set; } + + /// 启用 + Boolean Enable { get; set; } + + /// 扩展1 + Int32 Ex1 { get; set; } + + /// 扩展2 + Decimal Ex2 { get; set; } + + /// 扩展3 + Double Ex3 { get; set; } + + /// 扩展4 + String? Ex4 { get; set; } + + /// 扩展5 + String? Ex5 { get; set; } + + /// 扩展6 + String? Ex6 { get; set; } + + /// 创建者 + String? CreateUser { get; set; } + + /// 创建用户 + Int32 CreateUserID { get; set; } + + /// 创建地址 + String? CreateIP { get; set; } + + /// 创建时间 + DateTime CreateTime { get; set; } + + /// 更新者 + String? UpdateUser { get; set; } + + /// 更新用户 + Int32 UpdateUserID { get; set; } + + /// 更新地址 + String? UpdateIP { get; set; } + + /// 更新时间 + DateTime UpdateTime { get; set; } + + /// 备注 + String? Remark { get; set; } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityInterfaces/IRole.cs b/XUnitTest.XCode/Code/EntityInterfaces/IRole.cs new file mode 100644 index 000000000..aa241f511 --- /dev/null +++ b/XUnitTest.XCode/Code/EntityInterfaces/IRole.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 角色 +public partial interface IRole +{ + #region 属性 + /// 编号 + Int32 ID { get; set; } + + /// 名称 + String Name { get; set; } + + /// 启用 + Boolean Enable { get; set; } + + /// 系统。用于业务系统开发使用,不受数据权限约束,禁止修改名称或删除 + Boolean IsSystem { get; set; } + + /// 权限。对不同资源的权限,逗号分隔,每个资源的权限子项竖线分隔 + String? Permission { get; set; } + + /// 排序 + Int32 Sort { get; set; } + + /// 扩展1 + Int32 Ex1 { get; set; } + + /// 扩展2 + Int32 Ex2 { get; set; } + + /// 扩展3 + Double Ex3 { get; set; } + + /// 扩展4 + String? Ex4 { get; set; } + + /// 扩展5 + String? Ex5 { get; set; } + + /// 扩展6 + String? Ex6 { get; set; } + + /// 创建者 + String? CreateUser { get; set; } + + /// 创建用户 + Int32 CreateUserID { get; set; } + + /// 创建地址 + String? CreateIP { get; set; } + + /// 创建时间 + DateTime CreateTime { get; set; } + + /// 更新者 + String? UpdateUser { get; set; } + + /// 更新用户 + Int32 UpdateUserID { get; set; } + + /// 更新地址 + String? UpdateIP { get; set; } + + /// 更新时间 + DateTime UpdateTime { get; set; } + + /// 备注 + String? Remark { get; set; } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityInterfaces/ITenant.cs b/XUnitTest.XCode/Code/EntityInterfaces/ITenant.cs new file mode 100644 index 000000000..be57b0c05 --- /dev/null +++ b/XUnitTest.XCode/Code/EntityInterfaces/ITenant.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 租户。多租户SAAS平台,用于隔离业务数据 +public partial interface ITenant +{ + #region 属性 + /// 编号 + Int32 Id { get; set; } + + /// 编码。唯一编码 + String? Code { get; set; } + + /// 名称。显示名称 + String? Name { get; set; } + + /// 启用 + Boolean Enable { get; set; } + + /// 管理者 + Int32 ManagerId { get; set; } + + /// 角色组。租户可选的角色集合,不同级别的租户所拥有的角色不一样,高级功能也会不同 + String? RoleIds { get; set; } + + /// 图标。附件路径 + String? Logo { get; set; } + + /// 数据库。分库用的数据库名 + String? DatabaseName { get; set; } + + /// 数据表。分表用的数据表前缀 + String? TableName { get; set; } + + /// 过期时间。达到该时间后,自动禁用租户,空表示永不过期 + DateTime Expired { get; set; } + + /// 描述 + String? Remark { get; set; } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityInterfaces/ITenantUser.cs b/XUnitTest.XCode/Code/EntityInterfaces/ITenantUser.cs new file mode 100644 index 000000000..738d1073c --- /dev/null +++ b/XUnitTest.XCode/Code/EntityInterfaces/ITenantUser.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 租户关系。用户选择租户进入系统后,以租户关系角色组替代自有角色组来进行鉴权 +public partial interface ITenantUser +{ + #region 属性 + /// 编号 + Int32 Id { get; set; } + + /// 租户 + Int32 TenantId { get; set; } + + /// 用户 + Int32 UserId { get; set; } + + /// 启用 + Boolean Enable { get; set; } + + /// 角色。用户在该租户所对应的主要角色,替换用户自身的角色组 + Int32 RoleId { get; set; } + + /// 角色组。次要角色集合 + String? RoleIds { get; set; } + + /// 描述 + String? Remark { get; set; } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityInterfaces/IUser.cs b/XUnitTest.XCode/Code/EntityInterfaces/IUser.cs index 498cd6537..f91628efa 100644 --- a/XUnitTest.XCode/Code/EntityInterfaces/IUser.cs +++ b/XUnitTest.XCode/Code/EntityInterfaces/IUser.cs @@ -5,7 +5,7 @@ using System.Runtime.Serialization; using System.Web.Script.Serialization; using System.Xml.Serialization; -namespace XCode.Membership; +namespace XCode.Membership666; /// 用户。用户帐号信息 public partial interface IUser diff --git a/XUnitTest.XCode/Code/EntityInterfaces/IUserLog.cs b/XUnitTest.XCode/Code/EntityInterfaces/IUserLog.cs new file mode 100644 index 000000000..88407e73b --- /dev/null +++ b/XUnitTest.XCode/Code/EntityInterfaces/IUserLog.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 用户日志 +public partial interface IUserLog +{ + #region 属性 + /// 编号 + Int64 ID { get; set; } + + /// 数据时间。按月分表 + DateTime DataTime { get; set; } + + /// 类别 + String? Category { get; set; } + + /// 操作 + String? Action { get; set; } + + /// 链接 + Int32 LinkID { get; set; } + + /// 成功 + Boolean Success { get; set; } + + /// 用户名 + String? UserName { get; set; } + + /// 扩展1 + Int32 Ex1 { get; set; } + + /// 扩展2 + Int32 Ex2 { get; set; } + + /// 扩展3 + Double Ex3 { get; set; } + + /// 扩展4 + String? Ex4 { get; set; } + + /// 扩展5 + String? Ex5 { get; set; } + + /// 扩展6 + String? Ex6 { get; set; } + + /// 性能追踪。用于APM性能追踪定位,还原该事件的调用链 + String? TraceId { get; set; } + + /// 创建者 + String? CreateUser { get; set; } + + /// 创建用户 + Int32 CreateUserID { get; set; } + + /// 创建地址 + String? CreateIP { get; set; } + + /// 时间 + DateTime CreateTime { get; set; } + + /// 详细信息 + String? Remark { get; set; } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityModels/AreaModel.cs b/XUnitTest.XCode/Code/EntityModels/AreaModel.cs new file mode 100644 index 000000000..bd882ade1 --- /dev/null +++ b/XUnitTest.XCode/Code/EntityModels/AreaModel.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 地区。行政区划数据,最高支持四级地址,9位数字 +public partial class AreaModel : IArea +{ + #region 属性 + /// 编码。行政区划编码 + public Int32 ID { get; set; } + + /// 名称 + public String? Name { get; set; } + + /// 全名 + public String? FullName { get; set; } + + /// 父级 + public Int32 ParentID { get; set; } + + /// 层级 + public Int32 Level { get; set; } + + /// 类型。省市县,自治州等 + public String? Kind { get; set; } + + /// 英文名 + public String? English { get; set; } + + /// 拼音 + public String? PinYin { get; set; } + + /// 简拼 + public String? JianPin { get; set; } + + /// 区号。电话区号 + public String? TelCode { get; set; } + + /// 邮编。邮政编码 + public String? ZipCode { get; set; } + + /// 经度 + public Double Longitude { get; set; } + + /// 纬度 + public Double Latitude { get; set; } + + /// 地址编码。字符串前缀相同越多,地理距离越近,8位精度19米,6位610米 + public String? GeoHash { get; set; } + + /// 启用 + public Boolean Enable { get; set; } + + /// 创建时间 + public DateTime CreateTime { get; set; } + + /// 更新时间 + public DateTime UpdateTime { get; set; } + + /// 备注 + public String? Remark { get; set; } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IArea model) + { + ID = model.ID; + Name = model.Name; + FullName = model.FullName; + ParentID = model.ParentID; + Level = model.Level; + Kind = model.Kind; + English = model.English; + PinYin = model.PinYin; + JianPin = model.JianPin; + TelCode = model.TelCode; + ZipCode = model.ZipCode; + Longitude = model.Longitude; + Latitude = model.Latitude; + GeoHash = model.GeoHash; + Enable = model.Enable; + CreateTime = model.CreateTime; + UpdateTime = model.UpdateTime; + Remark = model.Remark; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityModels/DepartmentModel.cs b/XUnitTest.XCode/Code/EntityModels/DepartmentModel.cs new file mode 100644 index 000000000..c614908b1 --- /dev/null +++ b/XUnitTest.XCode/Code/EntityModels/DepartmentModel.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 部门。组织机构,多级树状结构 +public partial class DepartmentModel : IDepartment +{ + #region 属性 + /// 编号 + public Int32 ID { get; set; } + + /// 租户 + public Int32 TenantId { get; set; } + + /// 代码 + public String? Code { get; set; } + + /// 名称 + public String Name { get; set; } = null!; + + /// 全名 + public String? FullName { get; set; } + + /// 父级 + public Int32 ParentID { get; set; } + + /// 层级。树状结构的层级 + public Int32 Level { get; set; } + + /// 排序。同级内排序 + public Int32 Sort { get; set; } + + /// 启用 + public Boolean Enable { get; set; } + + /// 可见 + public Boolean Visible { get; set; } + + /// 管理者 + public Int32 ManagerId { get; set; } + + /// 扩展1 + public Int32 Ex1 { get; set; } + + /// 扩展2 + public Int32 Ex2 { get; set; } + + /// 扩展3 + public Double Ex3 { get; set; } + + /// 扩展4 + public String? Ex4 { get; set; } + + /// 扩展5 + public String? Ex5 { get; set; } + + /// 扩展6 + public String? Ex6 { get; set; } + + /// 创建者 + public String? CreateUser { get; set; } + + /// 创建用户 + public Int32 CreateUserID { get; set; } + + /// 创建地址 + public String? CreateIP { get; set; } + + /// 创建时间 + public DateTime CreateTime { get; set; } + + /// 更新者 + public String? UpdateUser { get; set; } + + /// 更新用户 + public Int32 UpdateUserID { get; set; } + + /// 更新地址 + public String? UpdateIP { get; set; } + + /// 更新时间 + public DateTime UpdateTime { get; set; } + + /// 备注 + public String? Remark { get; set; } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IDepartment model) + { + ID = model.ID; + TenantId = model.TenantId; + Code = model.Code; + Name = model.Name; + FullName = model.FullName; + ParentID = model.ParentID; + Level = model.Level; + Sort = model.Sort; + Enable = model.Enable; + Visible = model.Visible; + ManagerId = model.ManagerId; + Ex1 = model.Ex1; + Ex2 = model.Ex2; + Ex3 = model.Ex3; + Ex4 = model.Ex4; + Ex5 = model.Ex5; + Ex6 = model.Ex6; + CreateUser = model.CreateUser; + CreateUserID = model.CreateUserID; + CreateIP = model.CreateIP; + CreateTime = model.CreateTime; + UpdateUser = model.UpdateUser; + UpdateUserID = model.UpdateUserID; + UpdateIP = model.UpdateIP; + UpdateTime = model.UpdateTime; + Remark = model.Remark; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityModels/LogModel.cs b/XUnitTest.XCode/Code/EntityModels/LogModel.cs index 57725b5fc..75a193f8f 100644 --- a/XUnitTest.XCode/Code/EntityModels/LogModel.cs +++ b/XUnitTest.XCode/Code/EntityModels/LogModel.cs @@ -5,13 +5,13 @@ using System.Runtime.Serialization; using System.Web.Script.Serialization; using System.Xml.Serialization; -namespace XCode.Membership; +namespace XCode.Membership666; /// 日志 public partial class LogModel : ILog { #region 属性 - /// 编号 + /// 编号。按天分表 public Int64 ID { get; set; } /// 类别 diff --git a/XUnitTest.XCode/Code/EntityModels/MemberLogModel.cs b/XUnitTest.XCode/Code/EntityModels/MemberLogModel.cs new file mode 100644 index 000000000..fbcd2c800 --- /dev/null +++ b/XUnitTest.XCode/Code/EntityModels/MemberLogModel.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 成员日志 +public partial class MemberLogModel : IMemberLog +{ + #region 属性 + /// 编号 + public Int64 ID { get; set; } + + /// 数据分区 + public String? Ds { get; set; } + + /// 类别 + public String? Category { get; set; } + + /// 操作 + public String? Action { get; set; } + + /// 链接 + public Int32 LinkID { get; set; } + + /// 成功 + public Boolean Success { get; set; } + + /// 用户名 + public String? UserName { get; set; } + + /// 扩展1 + public Int32 Ex1 { get; set; } + + /// 扩展2 + public Int32 Ex2 { get; set; } + + /// 扩展3 + public Double Ex3 { get; set; } + + /// 扩展4 + public String? Ex4 { get; set; } + + /// 扩展5 + public String? Ex5 { get; set; } + + /// 扩展6 + public String? Ex6 { get; set; } + + /// 性能追踪。用于APM性能追踪定位,还原该事件的调用链 + public String? TraceId { get; set; } + + /// 创建者 + public String? CreateUser { get; set; } + + /// 创建用户 + public Int32 CreateUserID { get; set; } + + /// 创建地址 + public String? CreateIP { get; set; } + + /// 时间 + public DateTime CreateTime { get; set; } + + /// 详细信息 + public String? Remark { get; set; } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IMemberLog model) + { + ID = model.ID; + Ds = model.Ds; + Category = model.Category; + Action = model.Action; + LinkID = model.LinkID; + Success = model.Success; + UserName = model.UserName; + Ex1 = model.Ex1; + Ex2 = model.Ex2; + Ex3 = model.Ex3; + Ex4 = model.Ex4; + Ex5 = model.Ex5; + Ex6 = model.Ex6; + TraceId = model.TraceId; + CreateUser = model.CreateUser; + CreateUserID = model.CreateUserID; + CreateIP = model.CreateIP; + CreateTime = model.CreateTime; + Remark = model.Remark; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityModels/MenuModel.cs b/XUnitTest.XCode/Code/EntityModels/MenuModel.cs new file mode 100644 index 000000000..754c949db --- /dev/null +++ b/XUnitTest.XCode/Code/EntityModels/MenuModel.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 菜单 +public partial class MenuModel : IMenu +{ + #region 属性 + /// 编号 + public Int32 ID { get; set; } + + /// 名称 + public String Name { get; set; } = null!; + + /// 显示名 + public String? DisplayName { get; set; } + + /// 全名 + public String? FullName { get; set; } + + /// 父编号 + public Int32 ParentID { get; set; } + + /// 链接 + public String? Url { get; set; } + + /// 排序 + public Int32 Sort { get; set; } + + /// 图标 + public String? Icon { get; set; } + + /// 可见 + public Boolean Visible { get; set; } + + /// 必要。必要的菜单,必须至少有角色拥有这些权限,如果没有则自动授权给系统角色 + public Boolean Necessary { get; set; } + + /// 新窗口。新窗口打开链接 + public Boolean NewWindow { get; set; } + + /// 权限子项。逗号分隔,每个权限子项名值竖线分隔 + public String? Permission { get; set; } + + /// 扩展1 + public Int32 Ex1 { get; set; } + + /// 扩展2 + public Int32 Ex2 { get; set; } + + /// 扩展3 + public Double Ex3 { get; set; } + + /// 扩展4 + public String? Ex4 { get; set; } + + /// 扩展5 + public String? Ex5 { get; set; } + + /// 扩展6 + public String? Ex6 { get; set; } + + /// 创建者 + public String? CreateUser { get; set; } + + /// 创建用户 + public Int32 CreateUserID { get; set; } + + /// 创建地址 + public String? CreateIP { get; set; } + + /// 创建时间 + public DateTime CreateTime { get; set; } + + /// 更新者 + public String? UpdateUser { get; set; } + + /// 更新用户 + public Int32 UpdateUserID { get; set; } + + /// 更新地址 + public String? UpdateIP { get; set; } + + /// 更新时间 + public DateTime UpdateTime { get; set; } + + /// 备注 + public String? Remark { get; set; } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IMenu model) + { + ID = model.ID; + Name = model.Name; + DisplayName = model.DisplayName; + FullName = model.FullName; + ParentID = model.ParentID; + Url = model.Url; + Sort = model.Sort; + Icon = model.Icon; + Visible = model.Visible; + Necessary = model.Necessary; + NewWindow = model.NewWindow; + Permission = model.Permission; + Ex1 = model.Ex1; + Ex2 = model.Ex2; + Ex3 = model.Ex3; + Ex4 = model.Ex4; + Ex5 = model.Ex5; + Ex6 = model.Ex6; + CreateUser = model.CreateUser; + CreateUserID = model.CreateUserID; + CreateIP = model.CreateIP; + CreateTime = model.CreateTime; + UpdateUser = model.UpdateUser; + UpdateUserID = model.UpdateUserID; + UpdateIP = model.UpdateIP; + UpdateTime = model.UpdateTime; + Remark = model.Remark; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityModels/ParameterModel.cs b/XUnitTest.XCode/Code/EntityModels/ParameterModel.cs new file mode 100644 index 000000000..65a5f7f82 --- /dev/null +++ b/XUnitTest.XCode/Code/EntityModels/ParameterModel.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 字典参数 +public partial class ParameterModel : IParameter +{ + #region 属性 + /// 编号 + public Int32 ID { get; set; } + + /// 用户。按用户区分参数,用户0表示系统级 + public Int32 UserID { get; set; } + + /// 类别 + public String? Category { get; set; } + + /// 名称 + public String? Name { get; set; } + + /// 数值 + public String? Value { get; set; } + + /// 长数值 + public String? LongValue { get; set; } + + /// 种类。0普通,21列表,22名值 + public XCode.Membership.ParameterKinds Kind { get; set; } + + /// 启用 + public Boolean Enable { get; set; } + + /// 扩展1 + public Int32 Ex1 { get; set; } + + /// 扩展2 + public Decimal Ex2 { get; set; } + + /// 扩展3 + public Double Ex3 { get; set; } + + /// 扩展4 + public String? Ex4 { get; set; } + + /// 扩展5 + public String? Ex5 { get; set; } + + /// 扩展6 + public String? Ex6 { get; set; } + + /// 创建者 + public String? CreateUser { get; set; } + + /// 创建用户 + public Int32 CreateUserID { get; set; } + + /// 创建地址 + public String? CreateIP { get; set; } + + /// 创建时间 + public DateTime CreateTime { get; set; } + + /// 更新者 + public String? UpdateUser { get; set; } + + /// 更新用户 + public Int32 UpdateUserID { get; set; } + + /// 更新地址 + public String? UpdateIP { get; set; } + + /// 更新时间 + public DateTime UpdateTime { get; set; } + + /// 备注 + public String? Remark { get; set; } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IParameter model) + { + ID = model.ID; + UserID = model.UserID; + Category = model.Category; + Name = model.Name; + Value = model.Value; + LongValue = model.LongValue; + Kind = model.Kind; + Enable = model.Enable; + Ex1 = model.Ex1; + Ex2 = model.Ex2; + Ex3 = model.Ex3; + Ex4 = model.Ex4; + Ex5 = model.Ex5; + Ex6 = model.Ex6; + CreateUser = model.CreateUser; + CreateUserID = model.CreateUserID; + CreateIP = model.CreateIP; + CreateTime = model.CreateTime; + UpdateUser = model.UpdateUser; + UpdateUserID = model.UpdateUserID; + UpdateIP = model.UpdateIP; + UpdateTime = model.UpdateTime; + Remark = model.Remark; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityModels/RoleModel.cs b/XUnitTest.XCode/Code/EntityModels/RoleModel.cs new file mode 100644 index 000000000..4cc5c12b7 --- /dev/null +++ b/XUnitTest.XCode/Code/EntityModels/RoleModel.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 角色 +public partial class RoleModel : IRole +{ + #region 属性 + /// 编号 + public Int32 ID { get; set; } + + /// 名称 + public String Name { get; set; } = null!; + + /// 启用 + public Boolean Enable { get; set; } + + /// 系统。用于业务系统开发使用,不受数据权限约束,禁止修改名称或删除 + public Boolean IsSystem { get; set; } + + /// 权限。对不同资源的权限,逗号分隔,每个资源的权限子项竖线分隔 + public String? Permission { get; set; } + + /// 排序 + public Int32 Sort { get; set; } + + /// 扩展1 + public Int32 Ex1 { get; set; } + + /// 扩展2 + public Int32 Ex2 { get; set; } + + /// 扩展3 + public Double Ex3 { get; set; } + + /// 扩展4 + public String? Ex4 { get; set; } + + /// 扩展5 + public String? Ex5 { get; set; } + + /// 扩展6 + public String? Ex6 { get; set; } + + /// 创建者 + public String? CreateUser { get; set; } + + /// 创建用户 + public Int32 CreateUserID { get; set; } + + /// 创建地址 + public String? CreateIP { get; set; } + + /// 创建时间 + public DateTime CreateTime { get; set; } + + /// 更新者 + public String? UpdateUser { get; set; } + + /// 更新用户 + public Int32 UpdateUserID { get; set; } + + /// 更新地址 + public String? UpdateIP { get; set; } + + /// 更新时间 + public DateTime UpdateTime { get; set; } + + /// 备注 + public String? Remark { get; set; } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IRole model) + { + ID = model.ID; + Name = model.Name; + Enable = model.Enable; + IsSystem = model.IsSystem; + Permission = model.Permission; + Sort = model.Sort; + Ex1 = model.Ex1; + Ex2 = model.Ex2; + Ex3 = model.Ex3; + Ex4 = model.Ex4; + Ex5 = model.Ex5; + Ex6 = model.Ex6; + CreateUser = model.CreateUser; + CreateUserID = model.CreateUserID; + CreateIP = model.CreateIP; + CreateTime = model.CreateTime; + UpdateUser = model.UpdateUser; + UpdateUserID = model.UpdateUserID; + UpdateIP = model.UpdateIP; + UpdateTime = model.UpdateTime; + Remark = model.Remark; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityModels/TenantModel.cs b/XUnitTest.XCode/Code/EntityModels/TenantModel.cs new file mode 100644 index 000000000..4ad3ec503 --- /dev/null +++ b/XUnitTest.XCode/Code/EntityModels/TenantModel.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 租户。多租户SAAS平台,用于隔离业务数据 +public partial class TenantModel : ITenant +{ + #region 属性 + /// 编号 + public Int32 Id { get; set; } + + /// 编码。唯一编码 + public String? Code { get; set; } + + /// 名称。显示名称 + public String? Name { get; set; } + + /// 启用 + public Boolean Enable { get; set; } + + /// 管理者 + public Int32 ManagerId { get; set; } + + /// 角色组。租户可选的角色集合,不同级别的租户所拥有的角色不一样,高级功能也会不同 + public String? RoleIds { get; set; } + + /// 图标。附件路径 + public String? Logo { get; set; } + + /// 数据库。分库用的数据库名 + public String? DatabaseName { get; set; } + + /// 数据表。分表用的数据表前缀 + public String? TableName { get; set; } + + /// 过期时间。达到该时间后,自动禁用租户,空表示永不过期 + public DateTime Expired { get; set; } + + /// 描述 + public String? Remark { get; set; } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(ITenant model) + { + Id = model.Id; + Code = model.Code; + Name = model.Name; + Enable = model.Enable; + ManagerId = model.ManagerId; + RoleIds = model.RoleIds; + Logo = model.Logo; + DatabaseName = model.DatabaseName; + TableName = model.TableName; + Expired = model.Expired; + Remark = model.Remark; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityModels/TenantUserModel.cs b/XUnitTest.XCode/Code/EntityModels/TenantUserModel.cs new file mode 100644 index 000000000..b108dd559 --- /dev/null +++ b/XUnitTest.XCode/Code/EntityModels/TenantUserModel.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 租户关系。用户选择租户进入系统后,以租户关系角色组替代自有角色组来进行鉴权 +public partial class TenantUserModel : ITenantUser +{ + #region 属性 + /// 编号 + public Int32 Id { get; set; } + + /// 租户 + public Int32 TenantId { get; set; } + + /// 用户 + public Int32 UserId { get; set; } + + /// 启用 + public Boolean Enable { get; set; } + + /// 角色。用户在该租户所对应的主要角色,替换用户自身的角色组 + public Int32 RoleId { get; set; } + + /// 角色组。次要角色集合 + public String? RoleIds { get; set; } + + /// 描述 + public String? Remark { get; set; } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(ITenantUser model) + { + Id = model.Id; + TenantId = model.TenantId; + UserId = model.UserId; + Enable = model.Enable; + RoleId = model.RoleId; + RoleIds = model.RoleIds; + Remark = model.Remark; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityModels/UserLogModel.cs b/XUnitTest.XCode/Code/EntityModels/UserLogModel.cs new file mode 100644 index 000000000..f1a7134fe --- /dev/null +++ b/XUnitTest.XCode/Code/EntityModels/UserLogModel.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using System.Web.Script.Serialization; +using System.Xml.Serialization; + +namespace XCode.Membership666; + +/// 用户日志 +public partial class UserLogModel : IUserLog +{ + #region 属性 + /// 编号 + public Int64 ID { get; set; } + + /// 数据时间。按月分表 + public DateTime DataTime { get; set; } + + /// 类别 + public String? Category { get; set; } + + /// 操作 + public String? Action { get; set; } + + /// 链接 + public Int32 LinkID { get; set; } + + /// 成功 + public Boolean Success { get; set; } + + /// 用户名 + public String? UserName { get; set; } + + /// 扩展1 + public Int32 Ex1 { get; set; } + + /// 扩展2 + public Int32 Ex2 { get; set; } + + /// 扩展3 + public Double Ex3 { get; set; } + + /// 扩展4 + public String? Ex4 { get; set; } + + /// 扩展5 + public String? Ex5 { get; set; } + + /// 扩展6 + public String? Ex6 { get; set; } + + /// 性能追踪。用于APM性能追踪定位,还原该事件的调用链 + public String? TraceId { get; set; } + + /// 创建者 + public String? CreateUser { get; set; } + + /// 创建用户 + public Int32 CreateUserID { get; set; } + + /// 创建地址 + public String? CreateIP { get; set; } + + /// 时间 + public DateTime CreateTime { get; set; } + + /// 详细信息 + public String? Remark { get; set; } + #endregion + + #region 拷贝 + /// 拷贝模型对象 + /// 模型 + public void Copy(IUserLog model) + { + ID = model.ID; + DataTime = model.DataTime; + Category = model.Category; + Action = model.Action; + LinkID = model.LinkID; + Success = model.Success; + UserName = model.UserName; + Ex1 = model.Ex1; + Ex2 = model.Ex2; + Ex3 = model.Ex3; + Ex4 = model.Ex4; + Ex5 = model.Ex5; + Ex6 = model.Ex6; + TraceId = model.TraceId; + CreateUser = model.CreateUser; + CreateUserID = model.CreateUserID; + CreateIP = model.CreateIP; + CreateTime = model.CreateTime; + Remark = model.Remark; + } + #endregion +} diff --git a/XUnitTest.XCode/Code/EntityModels/UserModel.cs b/XUnitTest.XCode/Code/EntityModels/UserModel.cs index 9ad684af1..c48478196 100644 --- a/XUnitTest.XCode/Code/EntityModels/UserModel.cs +++ b/XUnitTest.XCode/Code/EntityModels/UserModel.cs @@ -5,7 +5,7 @@ using System.Runtime.Serialization; using System.Web.Script.Serialization; using System.Xml.Serialization; -namespace XCode.Membership; +namespace XCode.Membership666; /// 用户。用户帐号信息 public partial class UserModel : IUser diff --git a/XUnitTest.XCode/Code/Member.xml b/XUnitTest.XCode/Code/Member.xml index 5aff6344d..603a04505 100644 --- a/XUnitTest.XCode/Code/Member.xml +++ b/XUnitTest.XCode/Code/Member.xml @@ -8,7 +8,7 @@ Entity - XCode.Membership + XCode.Membership666 ..\..\XUnitTest.XCode\Code @@ -245,7 +245,7 @@ - + @@ -315,5 +315,61 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/XUnitTest.XCode/Code/Member2.xml b/XUnitTest.XCode/Code/Member2.xml index 3f4493221..6257c996a 100644 --- a/XUnitTest.XCode/Code/Member2.xml +++ b/XUnitTest.XCode/Code/Member2.xml @@ -8,7 +8,7 @@ Entity - XCode.Membership + XCode.Membership666 ..\..\XUnitTest.XCode\Code @@ -245,7 +245,7 @@ - + @@ -315,5 +315,61 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/XUnitTest.XCode/Code/entity_log_normal.cs b/XUnitTest.XCode/Code/entity_log_normal.cs index ed3a2cd0a..ebfa202fd 100644 --- a/XUnitTest.XCode/Code/entity_log_normal.cs +++ b/XUnitTest.XCode/Code/entity_log_normal.cs @@ -288,6 +288,17 @@ public partial class Log } #endregion + #region 数据清理 + /// 清理指定时间段内的数据 + /// 开始时间。未指定时清理小于指定时间的所有数据 + /// 结束时间 + /// 清理行数 + public static Int32 DeleteWith(DateTime start, DateTime end) + { + return Delete(_.ID.Between(start, end, Meta.Factory.Snow)); + } + #endregion + #region 字段名 /// 取得日志字段信息的快捷方式 public partial class _ diff --git a/XUnitTest.XCode/XUnitTest.XCode.csproj b/XUnitTest.XCode/XUnitTest.XCode.csproj index 8a0311074..590253bb4 100644 --- a/XUnitTest.XCode/XUnitTest.XCode.csproj +++ b/XUnitTest.XCode/XUnitTest.XCode.csproj @@ -13,23 +13,10 @@ - - - - - - - - - - - - - @@ -48,6 +35,32 @@ + + + + PreserveNewest + + + + PreserveNewest + + + + PreserveNewest + + + + PreserveNewest + + + + PreserveNewest + + + + PreserveNewest + + PreserveNewest @@ -61,39 +74,6 @@ PreserveNewest - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Always - - - PreserveNewest - - - PreserveNewest - PreserveNewest @@ -109,12 +89,6 @@ PreserveNewest - - PreserveNewest - - - PreserveNewest -