Supports dynamic class creation

This commit is contained in:
sunkaixuan 2023-03-20 20:23:55 +08:00
parent 6f3d45230b
commit 593708fcff
13 changed files with 271 additions and 1 deletions

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace SqlSugar
{
public static class DynamicBuilderHelper
{
public static Type CreateDynamicClass(string className, List<PropertyMetadata> properties, TypeAttributes attributes = TypeAttributes.Public, List<CustomAttributeBuilder> classCustomAttributes = null, Type baseType = null, Type[] interfaces = null)
{
TypeBuilder typeBuilder = EmitTool.CreateTypeBuilder(className, attributes, baseType, interfaces);
if (classCustomAttributes != null)
{
foreach (var attributeBuilder in classCustomAttributes)
{
typeBuilder.SetCustomAttribute(attributeBuilder);
}
}
foreach (PropertyMetadata property in properties)
{
EmitTool.CreateProperty(typeBuilder, property.Name, property.Type, property.CustomAttributes);
}
Type dynamicType = typeBuilder.CreateTypeInfo().AsType();
return dynamicType;
}
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace SqlSugar
{
internal class EmitTool
{
internal static ModuleBuilder CreateModuleBuilder()
{
AssemblyBuilder assemblyBuilder = CreateAssembly();
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");
return moduleBuilder;
}
internal static AssemblyBuilder CreateAssembly()
{
AssemblyName assemblyName = new AssemblyName($"DynamicAssembly_{Guid.NewGuid():N}");
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect);
return assemblyBuilder;
}
internal static TypeBuilder CreateTypeBuilder(string className, TypeAttributes attributes, Type baseType, Type[] interfaces)
{
ModuleBuilder moduleBuilder = EmitTool.CreateModuleBuilder();
TypeBuilder typeBuilder = moduleBuilder.DefineType(className, attributes, baseType, interfaces);
return typeBuilder;
}
internal static PropertyBuilder CreateProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType, IEnumerable<CustomAttributeBuilder> propertyCustomAttributes = null)
{
FieldBuilder fieldBuilder = typeBuilder.DefineField($"_{propertyName}", propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, null);
MethodBuilder getterBuilder = typeBuilder.DefineMethod($"get_{propertyName}", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getterIL = getterBuilder.GetILGenerator();
getterIL.Emit(OpCodes.Ldarg_0);
getterIL.Emit(OpCodes.Ldfld, fieldBuilder);
getterIL.Emit(OpCodes.Ret);
MethodBuilder setterBuilder = typeBuilder.DefineMethod($"set_{propertyName}", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new[] { propertyType });
ILGenerator setterIL = setterBuilder.GetILGenerator();
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldarg_1);
setterIL.Emit(OpCodes.Stfld, fieldBuilder);
setterIL.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getterBuilder);
propertyBuilder.SetSetMethod(setterBuilder);
if (propertyCustomAttributes != null)
{
foreach (var attributeBuilder in propertyCustomAttributes)
{
propertyBuilder.SetCustomAttribute(attributeBuilder);
}
}
return propertyBuilder;
}
}
}

View File

@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace SqlSugar
{
public partial class DynamicBuilder
{
private CustomAttributeBuilder GetEntity(SugarTable sugarTable)
{
Type attributeType = typeof(SugarTable);
ConstructorInfo attributeCtor = attributeType.GetConstructor(new Type[] { typeof(string) });
CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(attributeCtor, new object[] { "" },
new PropertyInfo[] {
attributeType.GetProperty(nameof(SugarTable.TableName)),
attributeType.GetProperty(nameof(SugarTable.TableDescription)) ,
attributeType.GetProperty(nameof(SugarTable.IsDisabledUpdateAll)) ,
attributeType.GetProperty(nameof(SugarTable.IsDisabledDelete))
}
, new object[] {
sugarTable.TableName,
sugarTable.TableDescription ,
sugarTable.IsDisabledUpdateAll,
sugarTable.IsDisabledDelete
});
return attributeBuilder;
}
private CustomAttributeBuilder GetProperty(SugarColumn sugarTable)
{
Type attributeType = typeof(SugarColumn);
ConstructorInfo attributeCtor = attributeType.GetConstructor(new Type[] { });
CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(attributeCtor, new object[] { },
new PropertyInfo[] {
attributeType.GetProperty(nameof(SugarColumn.IsPrimaryKey)),
attributeType.GetProperty(nameof(SugarColumn.IsIdentity)),
attributeType.GetProperty(nameof(SugarColumn.DefaultValue)),
attributeType.GetProperty(nameof(SugarColumn.Length)),
attributeType.GetProperty(nameof(SugarColumn.DecimalDigits)),
attributeType.GetProperty(nameof(SugarColumn.ColumnDataType)),
attributeType.GetProperty(nameof(SugarColumn.IsNullable)),
attributeType.GetProperty(nameof(SugarColumn.ColumnDescription)),
attributeType.GetProperty(nameof(SugarColumn.OracleSequenceName)),
attributeType.GetProperty(nameof(SugarColumn.IsIgnore)),
attributeType.GetProperty(nameof(SugarColumn.IsJson)),
attributeType.GetProperty(nameof(SugarColumn.IsOnlyIgnoreInsert)),
attributeType.GetProperty(nameof(SugarColumn.IsOnlyIgnoreUpdate)),
attributeType.GetProperty(nameof(SugarColumn.OldColumnName)),
attributeType.GetProperty(nameof(SugarColumn.SqlParameterDbType)),
attributeType.GetProperty(nameof(SugarColumn.SqlParameterSize)),
attributeType.GetProperty(nameof(SugarColumn.IsArray))
}
, new object[] {
sugarTable.IsPrimaryKey,
sugarTable.IsIdentity,
sugarTable.DefaultValue,
sugarTable.Length,
sugarTable.DecimalDigits,
sugarTable.ColumnDataType,
sugarTable.IsNullable,
sugarTable.ColumnDescription,
sugarTable.OracleSequenceName,
sugarTable.IsIgnore,
sugarTable.IsJson,
sugarTable.IsOnlyIgnoreInsert,
sugarTable.IsOnlyIgnoreUpdate,
sugarTable.OldColumnName,
sugarTable.SqlParameterDbType,
sugarTable.SqlParameterSize,
sugarTable.IsArray
});
return attributeBuilder;
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace SqlSugar
{
public partial class DynamicBuilder
{
List<PropertyMetadata> propertyAttr = new List<PropertyMetadata>();
List<CustomAttributeBuilder> entityAttr = new List<CustomAttributeBuilder>();
string entityName { get; set; }
Type baseType = null;
Type[] interfaces = null;
private SqlSugarProvider context;
public DynamicBuilder(SqlSugarProvider context)
{
this.context = context;
}
public DynamicBuilder CreateClass(string entityName, SugarTable table, Type baseType = null, Type[] interfaces = null)
{
this.baseType = baseType;
this.interfaces = interfaces;
this.entityName = entityName;
this.entityAttr = new List<CustomAttributeBuilder>() { GetEntity(table) };
return this;
}
public DynamicBuilder CreateProperty(string propertyName, Type properyType, SugarColumn table)
{
PropertyMetadata addItem = new PropertyMetadata();
addItem.Name = propertyName;
addItem.Type = properyType;
addItem.CustomAttributes = new List<CustomAttributeBuilder>() { GetProperty(table) };
this.propertyAttr.Add(addItem);
return this;
}
public Type BuilderType()
{
return DynamicBuilderHelper.CreateDynamicClass(this.entityName, propertyAttr, TypeAttributes.Public, this.entityAttr, baseType, interfaces);
}
}
}

View File

@ -155,6 +155,10 @@ namespace SqlSugar
{
return "";
}
if (entityType.Assembly.IsDynamic&& entityType.Assembly.FullName.StartsWith("Dynamic"))
{
return null;
}
var path = entityType.Assembly.Location;
if (string.IsNullOrEmpty(path))
{

View File

@ -1624,6 +1624,10 @@ namespace SqlSugar
#endregion
#region Other
public DynamicBuilder DynamicBuilder()
{
return new DynamicBuilder(this.Context);
}
public void Tracking<T>(T data) where T : class, new()
{
if (data != null)

View File

@ -786,6 +786,10 @@ namespace SqlSugar
{
return new SqlSugarClient(UtilMethods.CopyConfig(this.Ado.Context.CurrentConnectionConfig));
}
public DynamicBuilder DynamicBuilder()
{
return ScopedContext.DynamicBuilder();
}
public void Tracking<T>(T data) where T : class, new()
{
ScopedContext.Tracking(data);

View File

@ -8,7 +8,7 @@ namespace SqlSugar
{
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public class SugarTable : Attribute {
private SugarTable() { }
public SugarTable() { }
public string TableName { get; set; }
public string TableDescription { get; set; }
public bool IsDisabledDelete { get; set; }

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
namespace SqlSugar
{
public class PropertyMetadata
{
public string Name { get; set; }
public Type Type { get; set; }
public IEnumerable<CustomAttributeBuilder> CustomAttributes { get; set; }
}
}

View File

@ -45,6 +45,7 @@ namespace SqlSugar
#endregion
#region Other methods
DynamicBuilder DynamicBuilder();
void Tracking<T>(T data) where T : class, new();
void Tracking<T>(List<T> data) where T : class, new();
SqlSugarClient CopyNew();

View File

@ -88,6 +88,9 @@
<Compile Include="Abstract\DeleteProvider\LogicDeleteProvider.cs" />
<Compile Include="Abstract\DeleteProvider\SplitTableDeleteByObjectProvider.cs" />
<Compile Include="Abstract\DeleteProvider\SplitTableDeleteProvider.cs" />
<Compile Include="Abstract\DynamicBuilder\Helper.cs" />
<Compile Include="Abstract\DynamicBuilder\EmitTool.cs" />
<Compile Include="Abstract\DynamicBuilder\Master.cs" />
<Compile Include="Abstract\EntityMaintenance\EntityColumnExtension.cs" />
<Compile Include="Abstract\EntityMaintenance\EntityMaintenance.cs" />
<Compile Include="Abstract\ExecuteNavProvider\NavContext.cs" />
@ -140,6 +143,7 @@
<Compile Include="Abstract\UpdateProvider\UpdateMethodInfo.cs" />
<Compile Include="Abstract\UpdateProvider\UpdateableHelper.cs" />
<Compile Include="Abstract\UpdateProvider\SplitTableUpdateByObjectProvider.cs" />
<Compile Include="Entities\PropertyMetadata.cs" />
<Compile Include="Entities\DbFastestProperties.cs" />
<Compile Include="Entities\DefaultCustom.cs" />
<Compile Include="Entities\DeleteNavOptions.cs" />
@ -424,6 +428,7 @@
<Compile Include="Abstract\SugarProvider\SqlSugarScopeProvider.cs" />
<Compile Include="Utilities\CallContext.cs" />
<Compile Include="Utilities\CallContextAsync.cs" />
<Compile Include="Abstract\DynamicBuilder\DynamicBuilderHelper.cs" />
<Compile Include="Utilities\FastCopy.cs" />
<Compile Include="Utilities\ExpressionBuilderHelper.cs" />
<Compile Include="Utilities\CommonExtensions.cs" />

View File

@ -1156,6 +1156,10 @@ namespace SqlSugar
#endregion
#region Other method
public DynamicBuilder DynamicBuilder()
{
return this.Context.DynamicBuilder();
}
public void Tracking<T>(T data) where T : class, new()
{
this.Context.Tracking(data);

View File

@ -835,6 +835,10 @@ namespace SqlSugar
{
return new SqlSugarClient(UtilMethods.CopyConfig(this.Ado.Context.CurrentConnectionConfig));
}
public DynamicBuilder DynamicBuilder()
{
return ScopedContext.DynamicBuilder();
}
public void Tracking<T>(T data) where T : class, new()
{
ScopedContext.Tracking(data);