From bb1fd88f79dfbfb3efcd1f1bd6bc2e03175aa1c4 Mon Sep 17 00:00:00 2001 From: d4ilys <963922242@qq.com> Date: Mon, 15 May 2023 10:53:13 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E5=9F=BA=E7=B1=BB=E5=B1=9E=E6=80=A7abstrac?= =?UTF-8?q?t/virtual=E6=94=AF=E6=8C=81override?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DynamicEntity/DynamicEntityTest.cs | 131 +++++++++++++++++- FreeSql/Extensions/DynamicEntityExtensions.cs | 110 ++++++++++++++- FreeSql/FreeSql.xml | 78 ----------- 3 files changed, 233 insertions(+), 86 deletions(-) diff --git a/FreeSql.Tests/FreeSql.Tests/DynamicEntity/DynamicEntityTest.cs b/FreeSql.Tests/FreeSql.Tests/DynamicEntity/DynamicEntityTest.cs index c1385540..3c988ea8 100644 --- a/FreeSql.Tests/FreeSql.Tests/DynamicEntity/DynamicEntityTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/DynamicEntity/DynamicEntityTest.cs @@ -33,12 +33,14 @@ namespace FreeSql.Tests.DynamicEntity //根据Type生成表 fsql.CodeFirst.SyncStructure(table.Type); fsql.Insert().AsType(table.Type).AppendData(instance).ExecuteAffrows(); + var objects = fsql.Select().AsType(table.Type).ToList(); } [Fact] public void AttributeTest() { - var table = fsql.CodeFirst.DynamicEntity("AttributeUsers", new TableAttribute() { Name = "T_Attribute_User" }, + var table = fsql.CodeFirst.DynamicEntity("AttributeUsers", + new TableAttribute() { Name = "T_Attribute_User" }, new IndexAttribute("Name_Index1", "Name", false)) .Property("Id", typeof(int), new ColumnAttribute() { IsPrimary = true, IsIdentity = true, Position = 1 }) @@ -80,9 +82,122 @@ namespace FreeSql.Tests.DynamicEntity //根据Type生成表 fsql.CodeFirst.SyncStructure(table.Type); fsql.Insert().AsType(table.Type).AppendData(instance).ExecuteAffrows(); + var objects = fsql.Select().AsType(table.Type).ToList(); + } + + [Fact] + public void SuperClassVirtualOverrideTest() + { + var table = fsql.CodeFirst.DynamicEntity("Role_VirtualOverride", + new TableAttribute() { Name = "T_Role_VirtualOverride" }, + new IndexAttribute("Name_Index2", "Name", false)) + .Extend(typeof(BaseModelOverride)) + .Property("Id", typeof(int), + new ColumnAttribute() { IsPrimary = true, IsIdentity = true, Position = 1 }) + .Property("Name", typeof(string), + new ColumnAttribute() { StringLength = 20, Position = 2 }) + .Property("Operators", typeof(string), true) //重写 virtual 属性 + .Build(); + var dict = new Dictionary + { + ["Name"] = "系统管理员", + ["UpdateTime"] = DateTime.Now, + ["UpdatePerson"] = "admin", + ["Operators"] = "manager" + }; + var instance = table.CreateInstance(dict); + //根据Type生成表 + fsql.CodeFirst.SyncStructure(table.Type); + fsql.Insert().AsType(table.Type).AppendData(instance).ExecuteAffrows(); + var objects = fsql.Select().AsType(table.Type).ToList(); + } + + [Fact] + public void SuperClassBaseModelAbstractTest() + { + var table = fsql.CodeFirst.DynamicEntity("Role_AbstractOverride", + new TableAttribute() { Name = "T_Role_AbstractOverride" }, + new IndexAttribute("Name_Index2", "Name", false)) + .Extend(typeof(BaseModelOverride)) + .Property("Id", typeof(int), + new ColumnAttribute() { IsPrimary = true, IsIdentity = true, Position = 1 }) + .Property("Name", typeof(string), + new ColumnAttribute() { StringLength = 20, Position = 2 }) + .Property("Operators", typeof(string), true) //重写 abstract 属性 + .Build(); + var dict = new Dictionary + { + ["Name"] = "系统管理员", + ["UpdateTime"] = DateTime.Now, + ["UpdatePerson"] = "admin", + ["Operators"] = "manager" + }; + var instance = table.CreateInstance(dict); + //根据Type生成表 + fsql.CodeFirst.SyncStructure(table.Type); + fsql.Insert().AsType(table.Type).AppendData(instance).ExecuteAffrows(); + var objects = fsql.Select().AsType(table.Type).ToList(); + } + + [Fact] + public void SuperClassBaseModelAbstractAndVirtualTest() + { + var table = fsql.CodeFirst.DynamicEntity("Role_AbstractAndVirtualOverride", + new TableAttribute() { Name = "Role_AbstractAndVirtualOverride" }, + new IndexAttribute("Name_Index2", "Name", false)) + .Extend(typeof(BaseModelOverride)) + .Property("Id", typeof(int), + new ColumnAttribute() { IsPrimary = true, IsIdentity = true, Position = 1 }) + .Property("Name", typeof(string), + new ColumnAttribute() { StringLength = 20, Position = 2 }) + .Property("Operators", typeof(string), true) //重写 abstract 属性 + .Property("Operators2", typeof(string), true) //重写 virtual 属性 + .Build(); + var dict = new Dictionary + { + ["Name"] = "系统管理员", + ["UpdateTime"] = DateTime.Now, + ["UpdatePerson"] = "admin", + ["Operators"] = "manager", + ["Operators2"] = "manager2" + }; + var instance = table.CreateInstance(dict); + //根据Type生成表 + fsql.CodeFirst.SyncStructure(table.Type); + fsql.Insert().AsType(table.Type).AppendData(instance).ExecuteAffrows(); + var objects = fsql.Select().AsType(table.Type).ToList(); } } + public class BaseModel + { + [Column(Position = 99)] public DateTime UpdateTime { get; set; } + + [Column(Position = 100, StringLength = 20)] + public string UpdatePerson { get; set; } + } + + public class BaseModelOverride + { + [Column(Position = 99)] public DateTime UpdateTime { get; set; } + + [Column(Position = 100, StringLength = 20)] + public string UpdatePerson { get; set; } + + public virtual string Operators { get; set; } + } + + public abstract class BaseModelAbstract + { + [Column(Position = 99)] public DateTime UpdateTime { get; set; } + + [Column(Position = 100, StringLength = 20)] + public string UpdatePerson { get; set; } + + public abstract string Operators { get; set; } + } + + public abstract class BaseModelAbstractAndVirtual { [Column(Position = 99)] public DateTime UpdateTime @@ -95,5 +210,17 @@ namespace FreeSql.Tests.DynamicEntity { get; set; } + + public abstract string Operators + { + get; set; + } + + + public virtual string Operators2 + { + get; set; + } } -} \ No newline at end of file +} + diff --git a/FreeSql/Extensions/DynamicEntityExtensions.cs b/FreeSql/Extensions/DynamicEntityExtensions.cs index f4659e1e..0ae32e0e 100644 --- a/FreeSql/Extensions/DynamicEntityExtensions.cs +++ b/FreeSql/Extensions/DynamicEntityExtensions.cs @@ -1,7 +1,7 @@ // by: Daily #if net40 || NETSTANDARD2_0 -# else +#else using FreeSql; using FreeSql.DataAnnotations; @@ -23,7 +23,8 @@ public static class FreeSqlGlobalDynamicEntityExtensions /// 动态构建Class Type /// /// - public static DynamicCompileBuilder DynamicEntity(this ICodeFirst codeFirst, string className, params Attribute[] attributes) + public static DynamicCompileBuilder DynamicEntity(this ICodeFirst codeFirst, string className, + params Attribute[] attributes) { return new DynamicCompileBuilder((codeFirst as CodeFirstProvider)._orm, className, attributes); } @@ -43,8 +44,10 @@ public static class FreeSqlGlobalDynamicEntityExtensions if (dict.ContainsKey(key) == false) continue; table.ColumnsByCs[key].SetValue(instance, dict[key]); } + return instance; } + /// /// 根据实体对象,创建 table 对应的字典 /// @@ -94,12 +97,59 @@ namespace FreeSql.Extensions.DynamicEntity /// 属性类型 /// 属性标记的特性-支持多个 /// - public DynamicCompileBuilder Property(string propertyName, Type propertyType, params Attribute[] attributes) + public DynamicCompileBuilder Property(string propertyName, Type propertyType, + params Attribute[] attributes) { _properties.Add(new DynamicPropertyInfo() { PropertyName = propertyName, PropertyType = propertyType, + DefaultValue = null, + Attributes = attributes + }); + return this; + } + + /// + /// 配置属性 + /// + /// 属性名称 + /// 属性类型 + /// 该属性是否重写父类属性 + /// 属性标记的特性-支持多个 + /// + public DynamicCompileBuilder Property(string propertyName, Type propertyType, bool isOverride, + params Attribute[] attributes) + { + _properties.Add(new DynamicPropertyInfo() + { + PropertyName = propertyName, + PropertyType = propertyType, + DefaultValue = null, + IsOverride = isOverride, + Attributes = attributes + }); + return this; + } + + /// + /// 配置属性 + /// + /// 属性名称 + /// 属性类型 + /// 该属性是否重写父类属性 + /// 属性默认值 + /// 属性标记的特性-支持多个 + /// + public DynamicCompileBuilder Property(string propertyName, Type propertyType, bool isOverride, + object defaultValue, params Attribute[] attributes) + { + _properties.Add(new DynamicPropertyInfo() + { + PropertyName = propertyName, + PropertyType = propertyType, + DefaultValue = null, + IsOverride = isOverride, Attributes = attributes }); return this; @@ -162,10 +212,17 @@ namespace FreeSql.Extensions.DynamicEntity var field = typeBuilder.DefineField($"_{FirstCharToLower(propertyName)}", propertyType, FieldAttributes.Private); var firstCharToUpper = FirstCharToUpper(propertyName); + + MethodAttributes maAttributes = MethodAttributes.Public; + + if (pinfo.IsOverride) + { + maAttributes = MethodAttributes.Public | MethodAttributes.Virtual; + } + //设置属性方法 - var methodGet = typeBuilder.DefineMethod($"Get{firstCharToUpper}", MethodAttributes.Public, - propertyType, null); - var methodSet = typeBuilder.DefineMethod($"Set{firstCharToUpper}", MethodAttributes.Public, null, + var methodGet = typeBuilder.DefineMethod($"get_{firstCharToUpper}", maAttributes, propertyType, null); + var methodSet = typeBuilder.DefineMethod($"set_{firstCharToUpper}", maAttributes, null, new Type[] { propertyType }); var ilOfGet = methodGet.GetILGenerator(); @@ -179,12 +236,27 @@ namespace FreeSql.Extensions.DynamicEntity ilOfSet.Emit(OpCodes.Stfld, field); ilOfSet.Emit(OpCodes.Ret); + + //是否重写 + if (pinfo.IsOverride) + { + //重写Get、Set方法 + OverrideProperty(ref typeBuilder, methodGet, PropertyMethodEnum.GET, pinfo.PropertyName); + OverrideProperty(ref typeBuilder, methodSet, PropertyMethodEnum.SET, pinfo.PropertyName); + } + //设置属性 var propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, null); propertyBuilder.SetGetMethod(methodGet); propertyBuilder.SetSetMethod(methodSet); + //设置默认值 + if (pinfo.DefaultValue != null) + { + propertyBuilder.SetConstant(pinfo.DefaultValue); + } + foreach (var pinfoAttribute in pinfo.Attributes) { //设置特性 @@ -208,6 +280,23 @@ namespace FreeSql.Extensions.DynamicEntity propertyBuilder.SetCustomAttribute(customAttributeBuilder); } + /// + /// Override属性 + /// + /// + private void OverrideProperty(ref TypeBuilder typeBuilder, MethodBuilder methodBuilder, + PropertyMethodEnum methodEnum, + string propertyName) + { + //查找父类的属性信息 + var propertyInfo = typeBuilder.BaseType.GetProperty(propertyName); + if (propertyInfo == null) return; + var pm = methodEnum == PropertyMethodEnum.GET ? propertyInfo.GetGetMethod() : propertyInfo.GetSetMethod(); + //重写父类GET SET 方法 + typeBuilder.DefineMethodOverride(methodBuilder, pm); + } + + /// /// Emit动态创建出Class - Type /// @@ -233,6 +322,7 @@ namespace FreeSql.Extensions.DynamicEntity //创建类的Type对象 var type = typeBuilder.CreateType(); + return _fsql.CodeFirst.GetTableByEntity(type); } @@ -279,8 +369,16 @@ namespace FreeSql.Extensions.DynamicEntity { public string PropertyName { get; set; } = string.Empty; public Type PropertyType { get; set; } + public object DefaultValue { get; set; } + public bool IsOverride { get; set; } = false; public Attribute[] Attributes { get; set; } } + + enum PropertyMethodEnum + { + GET, + SET + } } } #endif \ No newline at end of file diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index aaffe163..5323d7da 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -6208,81 +6208,3 @@ -ew{id=1} - - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - - - - - 查询数据 - - - - - - - 查询数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - - - - - 删除数据 - - - - - - - 删除数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - - - - - 开启事务(不支持异步) - v1.5.0 关闭了线程事务超时自动提交的机制 - - 事务体 () => {} - - - - 开启事务(不支持异步) - v1.5.0 关闭了线程事务超时自动提交的机制 - - - 事务体 () => {} - - - - 数据库访问对象 - - - - - 所有拦截方法都在这里 - - - - - CodeFirst 模式开发相关方法 - - - - - DbFirst 模式开发相关方法 - - - - - 全局过滤设置,可默认附加为 Select/Update/Delete 条件 - - - -