- 基类属性abstract/virtual支持override,支持属性默认值

This commit is contained in:
d4ilys 2023-05-15 16:34:55 +08:00
parent bb1fd88f79
commit 4732ccde87
3 changed files with 219 additions and 34 deletions

View File

@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using FreeSql.DataAnnotations; using FreeSql.DataAnnotations;
using FreeSql.Extensions.DynamicEntity; using FreeSql.Extensions.DynamicEntity;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace FreeSql.Tests.DynamicEntity namespace FreeSql.Tests.DynamicEntity
@ -118,7 +119,7 @@ namespace FreeSql.Tests.DynamicEntity
var table = fsql.CodeFirst.DynamicEntity("Role_AbstractOverride", var table = fsql.CodeFirst.DynamicEntity("Role_AbstractOverride",
new TableAttribute() { Name = "T_Role_AbstractOverride" }, new TableAttribute() { Name = "T_Role_AbstractOverride" },
new IndexAttribute("Name_Index2", "Name", false)) new IndexAttribute("Name_Index2", "Name", false))
.Extend(typeof(BaseModelOverride)) .Extend(typeof(BaseModelAbstract))
.Property("Id", typeof(int), .Property("Id", typeof(int),
new ColumnAttribute() { IsPrimary = true, IsIdentity = true, Position = 1 }) new ColumnAttribute() { IsPrimary = true, IsIdentity = true, Position = 1 })
.Property("Name", typeof(string), .Property("Name", typeof(string),
@ -145,7 +146,7 @@ namespace FreeSql.Tests.DynamicEntity
var table = fsql.CodeFirst.DynamicEntity("Role_AbstractAndVirtualOverride", var table = fsql.CodeFirst.DynamicEntity("Role_AbstractAndVirtualOverride",
new TableAttribute() { Name = "Role_AbstractAndVirtualOverride" }, new TableAttribute() { Name = "Role_AbstractAndVirtualOverride" },
new IndexAttribute("Name_Index2", "Name", false)) new IndexAttribute("Name_Index2", "Name", false))
.Extend(typeof(BaseModelOverride)) .Extend(typeof(BaseModelAbstractAndVirtual))
.Property("Id", typeof(int), .Property("Id", typeof(int),
new ColumnAttribute() { IsPrimary = true, IsIdentity = true, Position = 1 }) new ColumnAttribute() { IsPrimary = true, IsIdentity = true, Position = 1 })
.Property("Name", typeof(string), .Property("Name", typeof(string),
@ -167,6 +168,32 @@ namespace FreeSql.Tests.DynamicEntity
fsql.Insert<object>().AsType(table.Type).AppendData(instance).ExecuteAffrows(); fsql.Insert<object>().AsType(table.Type).AppendData(instance).ExecuteAffrows();
var objects = fsql.Select<object>().AsType(table.Type).ToList(); var objects = fsql.Select<object>().AsType(table.Type).ToList();
} }
[Fact]
public void DefaultValueTest()
{
var table = fsql.CodeFirst.DynamicEntity("NormalUsers")
.Property("Id", typeof(string))
.Property("Age", typeof(int), false, 12)
.Property("Longs", typeof(long), false, 16666)
.Property("Dates", typeof(DateTime), false, "2023-05-15")
.Property("Name", typeof(char), false, '我')
.Property("Address", typeof(bool), false, false) //设置默认值
.Property("Money", typeof(double), false, 265421.02) //设置默认值
.Property("MoneyFloat", typeof(float), false, 26543.02) //设置默认值
.Property("MoneyDecimal", typeof(decimal), true, 2663.12560) //设置默认值
.Build();
var dict = new Dictionary<string, object>
{
["Id"] = Guid.NewGuid().ToString()
};
var instance = table.CreateInstance(dict);
//根据Type生成表
fsql.CodeFirst.SyncStructure(table.Type);
fsql.Insert<object>().AsType(table.Type).AppendData(instance).ExecuteAffrows();
var objects = fsql.Select<object>().AsType(table.Type).ToList();
}
} }
public class BaseModel public class BaseModel
@ -199,28 +226,14 @@ namespace FreeSql.Tests.DynamicEntity
public abstract class BaseModelAbstractAndVirtual public abstract class BaseModelAbstractAndVirtual
{ {
[Column(Position = 99)] [Column(Position = 99)] public DateTime UpdateTime { get; set; }
public DateTime UpdateTime
{
get; set;
}
[Column(Position = 100, StringLength = 20)] [Column(Position = 100, StringLength = 20)]
public string UpdatePerson public string UpdatePerson { get; set; }
{
get; set;
}
public abstract string Operators public abstract string Operators { get; set; }
{
get; set;
}
public virtual string Operators2 public virtual string Operators2 { get; set; }
{
get; set;
}
} }
} }

View File

@ -11,11 +11,15 @@ using FreeSql.Internal.Model;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Net.NetworkInformation;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
using System.Runtime.Serialization;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Xml.Serialization;
public static class FreeSqlGlobalDynamicEntityExtensions public static class FreeSqlGlobalDynamicEntityExtensions
{ {
@ -39,6 +43,12 @@ public static class FreeSqlGlobalDynamicEntityExtensions
{ {
if (table == null || dict == null) return null; if (table == null || dict == null) return null;
var instance = table.Type.CreateInstanceGetDefaultValue(); var instance = table.Type.CreateInstanceGetDefaultValue();
//加载默认值
var defaultValueInit = table.Type.GetMethod("DefaultValueInit");
if (defaultValueInit != null)
{
defaultValueInit.Invoke(instance, new object[0]);
}
foreach (var key in table.ColumnsByCs.Keys) foreach (var key in table.ColumnsByCs.Keys)
{ {
if (dict.ContainsKey(key) == false) continue; if (dict.ContainsKey(key) == false) continue;
@ -148,7 +158,7 @@ namespace FreeSql.Extensions.DynamicEntity
{ {
PropertyName = propertyName, PropertyName = propertyName,
PropertyType = propertyType, PropertyType = propertyType,
DefaultValue = null, DefaultValue = defaultValue,
IsOverride = isOverride, IsOverride = isOverride,
Attributes = attributes Attributes = attributes
}); });
@ -176,7 +186,7 @@ namespace FreeSql.Extensions.DynamicEntity
if (tableAttribute == null) continue; if (tableAttribute == null) continue;
var classCtorInfo = tableAttribute.GetType().GetConstructor(new Type[] { }); var classCtorInfo = tableAttribute.GetType().GetConstructor(Type.EmptyTypes);
var propertyInfos = tableAttribute.GetType().GetProperties().Where(p => p.CanWrite == true).ToArray(); var propertyInfos = tableAttribute.GetType().GetProperties().Where(p => p.CanWrite == true).ToArray();
@ -202,6 +212,7 @@ namespace FreeSql.Extensions.DynamicEntity
private void SetPropertys(ref TypeBuilder typeBuilder) private void SetPropertys(ref TypeBuilder typeBuilder)
{ {
var defaultValues = new Dictionary<FieldBuilder, object>();
foreach (var pinfo in _properties) foreach (var pinfo in _properties)
{ {
if (pinfo == null) if (pinfo == null)
@ -210,11 +221,12 @@ namespace FreeSql.Extensions.DynamicEntity
var propertyType = pinfo.PropertyType; var propertyType = pinfo.PropertyType;
//设置字段 //设置字段
var field = typeBuilder.DefineField($"_{FirstCharToLower(propertyName)}", propertyType, var field = typeBuilder.DefineField($"_{FirstCharToLower(propertyName)}", propertyType,
FieldAttributes.Private); FieldAttributes.Private | FieldAttributes.HasDefault);
var firstCharToUpper = FirstCharToUpper(propertyName); var firstCharToUpper = FirstCharToUpper(propertyName);
MethodAttributes maAttributes = MethodAttributes.Public; MethodAttributes maAttributes = MethodAttributes.Public;
//是否重写
if (pinfo.IsOverride) if (pinfo.IsOverride)
{ {
maAttributes = MethodAttributes.Public | MethodAttributes.Virtual; maAttributes = MethodAttributes.Public | MethodAttributes.Virtual;
@ -251,33 +263,95 @@ namespace FreeSql.Extensions.DynamicEntity
propertyBuilder.SetGetMethod(methodGet); propertyBuilder.SetGetMethod(methodGet);
propertyBuilder.SetSetMethod(methodSet); propertyBuilder.SetSetMethod(methodSet);
//设置默认值
if (pinfo.DefaultValue != null)
{
propertyBuilder.SetConstant(pinfo.DefaultValue);
}
foreach (var pinfoAttribute in pinfo.Attributes) foreach (var pinfoAttribute in pinfo.Attributes)
{ {
//设置特性 //设置特性
SetPropertyAttribute(ref propertyBuilder, pinfoAttribute); SetPropertyAttribute(ref propertyBuilder, pinfoAttribute);
} }
if (pinfo.DefaultValue != null)
{
defaultValues.Add(field, pinfo.DefaultValue);
}
}
//动态构建方法,设置默认值
var methodDefaultValue = typeBuilder.DefineMethod($"DefaultValueInit", MethodAttributes.Public, null, null);
var methodDefaultValueLlGenerator = methodDefaultValue.GetILGenerator();
foreach (var kv in defaultValues)
{
methodDefaultValueLlGenerator.Emit(OpCodes.Ldarg_0);
OpCodesAdapter(ref methodDefaultValueLlGenerator, kv.Key, kv.Value);
methodDefaultValueLlGenerator.Emit(OpCodes.Stfld, kv.Key);
}
methodDefaultValueLlGenerator.Emit(OpCodes.Ret);
}
//IL命令类型适配
private void OpCodesAdapter(ref ILGenerator generator, FieldInfo info, object value)
{
var fieldTypeName = info.FieldType.Name;
switch (fieldTypeName)
{
case "Int32":
generator.Emit(OpCodes.Ldc_I4, Convert.ToInt32(value));
break;
case "Boolean":
generator.Emit(OpCodes.Ldc_I4, Convert.ToInt32(value));
break;
case "Char":
generator.Emit(OpCodes.Ldc_I4, Convert.ToChar(value));
break;
case "String":
generator.Emit(OpCodes.Ldstr, Convert.ToString(value));
break;
case "DateTime":
generator.Emit(OpCodes.Ldstr, Convert.ToString(value));
generator.Emit(OpCodes.Call, typeof(DateTime).GetMethod("Parse", new[] { typeof(string) }));
break;
case "Int64":
generator.Emit(OpCodes.Ldc_I4, Convert.ToString(value));
generator.Emit(OpCodes.Conv_I8);
break;
case "Double":
generator.Emit(OpCodes.Ldc_R8, Convert.ToDouble(value));
break;
case "Single":
generator.Emit(OpCodes.Ldc_R4, Convert.ToSingle(value));
break;
case "Decimal":
Console.WriteLine(Convert.ToString(value));
generator.Emit(OpCodes.Ldstr, Convert.ToString(value));
generator.Emit(OpCodes.Call, typeof(Decimal).GetMethod("Parse", new[] { typeof(string) }));
break;
} }
} }
private void SetPropertyAttribute<T>(ref PropertyBuilder propertyBuilder, T tAttribute) private void SetPropertyAttribute<T>(ref PropertyBuilder propertyBuilder, T tAttribute)
{ {
if (tAttribute == null) return; if (tAttribute == null) return;
var propertyInfos = tAttribute.GetType().GetProperties().Where(p => p.CanWrite == true).ToArray(); var propertyInfos = tAttribute.GetType().GetProperties().Where(p => p.CanWrite == true).ToArray();
var constructor = tAttribute.GetType().GetConstructor(new Type[] { }); var constructor = tAttribute.GetType().GetConstructor(Type.EmptyTypes);
var propertyValues = new ArrayList(); var propertyValues = new ArrayList();
foreach (var propertyInfo in propertyInfos) foreach (var propertyInfo in propertyInfos)
propertyValues.Add(propertyInfo.GetValue(tAttribute)); propertyValues.Add(propertyInfo.GetValue(tAttribute));
var customAttributeBuilder = //可能存在有参构造
new CustomAttributeBuilder(constructor, new object[0], propertyInfos, propertyValues.ToArray()); //if (constructor == null)
//{
// var constructorTypes = propertyInfos.Select(p => p.PropertyType).ToList();
// constructor = tAttribute.GetType().GetConstructor(constructorTypes.ToArray());
// var customAttributeBuilder = new CustomAttributeBuilder(constructor, constructorTypes.ToArray(),
// propertyInfos, propertyValues.ToArray());
// propertyBuilder.SetCustomAttribute(customAttributeBuilder);
//}
//else
//{
var customAttributeBuilder = new CustomAttributeBuilder(constructor, new object[0], propertyInfos,
propertyValues.ToArray());
propertyBuilder.SetCustomAttribute(customAttributeBuilder); propertyBuilder.SetCustomAttribute(customAttributeBuilder);
// }
} }
/// <summary> /// <summary>

View File

@ -1073,6 +1073,82 @@
</summary> </summary>
<returns></returns> <returns></returns>
</member> </member>
<member name="T:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder">
<summary>
动态创建实体类型
</summary>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.#ctor(IFreeSql,System.String,System.Attribute[])">
<summary>
配置Class
</summary>
<param name="className">类名</param>
<param name="attributes">类标记的特性[Table(Name = "xxx")] [Index(xxxx)]</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Property(System.String,System.Type,System.Attribute[])">
<summary>
配置属性
</summary>
<param name="propertyName">属性名称</param>
<param name="propertyType">属性类型</param>
<param name="attributes">属性标记的特性-支持多个</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Property(System.String,System.Type,System.Boolean,System.Attribute[])">
<summary>
配置属性
</summary>
<param name="propertyName">属性名称</param>
<param name="propertyType">属性类型</param>
<param name="isOverride">该属性是否重写父类属性</param>
<param name="attributes">属性标记的特性-支持多个</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Property(System.String,System.Type,System.Boolean,System.Object,System.Attribute[])">
<summary>
配置属性
</summary>
<param name="propertyName">属性名称</param>
<param name="propertyType">属性类型</param>
<param name="isOverride">该属性是否重写父类属性</param>
<param name="defaultValue">属性默认值</param>
<param name="attributes">属性标记的特性-支持多个</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Extend(System.Type)">
<summary>
配置父类
</summary>
<param name="superClass">父类类型</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.OverrideProperty(System.Reflection.Emit.TypeBuilder@,System.Reflection.Emit.MethodBuilder,FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.PropertyMethodEnum,System.String)">
<summary>
Override属性
</summary>
<param name="typeBuilder"></param>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Build">
<summary>
Emit动态创建出Class - Type
</summary>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.FirstCharToLower(System.String)">
<summary>
首字母小写
</summary>
<param name="input"></param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.FirstCharToUpper(System.String)">
<summary>
首字母大写
</summary>
<param name="input"></param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetEntityKeyString(IFreeSql,System.Type,System.Object,System.Boolean,System.String)"> <member name="M:FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetEntityKeyString(IFreeSql,System.Type,System.Object,System.Boolean,System.String)">
<summary> <summary>
获取实体的主键值,以 "*|_,[,_|*" 分割,当任意一个主键属性无值时,返回 null 获取实体的主键值,以 "*|_,[,_|*" 分割,当任意一个主键属性无值时,返回 null
@ -5692,6 +5768,28 @@
请使用 fsql.InsertDict(dict) 方法插入字典数据 请使用 fsql.InsertDict(dict) 方法插入字典数据
</summary> </summary>
</member> </member>
<member name="M:FreeSqlGlobalDynamicEntityExtensions.DynamicEntity(FreeSql.ICodeFirst,System.String,System.Attribute[])">
<summary>
动态构建Class Type
</summary>
<returns></returns>
</member>
<member name="M:FreeSqlGlobalDynamicEntityExtensions.CreateInstance(FreeSql.Internal.Model.TableInfo,System.Collections.Generic.Dictionary{System.String,System.Object})">
<summary>
根据字典,创建 table 对应的实体对象
</summary>
<param name="table"></param>
<param name="dict"></param>
<returns></returns>
</member>
<member name="M:FreeSqlGlobalDynamicEntityExtensions.CreateDictionary(FreeSql.Internal.Model.TableInfo,System.Object)">
<summary>
根据实体对象,创建 table 对应的字典
</summary>
<param name="table"></param>
<param name="instance"></param>
<returns></returns>
</member>
<member name="M:FreeSqlGlobalExpressionCallExtensions.Between(System.DateTime,System.DateTime,System.DateTime)"> <member name="M:FreeSqlGlobalExpressionCallExtensions.Between(System.DateTime,System.DateTime,System.DateTime)">
<summary> <summary>
C# that >= between &amp;&amp; that &lt;= and<para></para> C# that >= between &amp;&amp; that &lt;= and<para></para>