Skip to content

Instantly share code, notes, and snippets.

@dalion619
Created September 4, 2018 07:57
Show Gist options
  • Save dalion619/86f4483130140bb62d90eeb009b423cb to your computer and use it in GitHub Desktop.
Save dalion619/86f4483130140bb62d90eeb009b423cb to your computer and use it in GitHub Desktop.
Create Dynamic Database Model Module
// Get tables and their columns
var databaseTableInfo = GetDatabaseTableInfo();
AppDomain domain = AppDomain.CurrentDomain;
AssemblyName aName = new AssemblyName("Example.DynamicMapping.DynamicDatabaseMapping");
AssemblyBuilder ab = domain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save);
System.Reflection.Emit.ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");
// Define mapping static class of the database
TypeBuilder typeDatabaseModel = mb.DefineType("Example.DynamicMapping.DynamicDatabaseMapping.DatabaseModels.DatabaseMapping", TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Sealed);
// Get base table class
Type tableBase = typeof(SqlTableModelBase);
ConstructorInfo tableBaseCtor = tableBase.GetConstructor(Type.EmptyTypes); // no parameters
// Get base column class
Type columnBase = typeof(SqlColumnModelBase);
ConstructorInfo fieldBaseCtor = columnBase.GetConstructor(new[] { typeof(string) });
// Needed for creating the class constructors in a loop
var tableFields = new List<ReflectionDefineField>();
foreach (var table in databaseTableInfo)
{
var columnFields = new List<ReflectionDefineField>();
TypeBuilder typeTable = mb.DefineType($"Example.DynamicMapping.DynamicDatabaseMapping.DatabaseModels.{table.Name}", TypeAttributes.Public, typeof(SqlTableModelBase));
// Create the column classes for the table
foreach (var column in table.Columns)
{
TypeBuilder typeColumn = mb.DefineType($"Example.DynamicMapping.DynamicDatabaseMapping.DatabaseModels.{table.Name}.{column.Name}", TypeAttributes.Public, typeof(SqlColumnModelBase));
ConstructorBuilder staticColumnConstructorBuilder =
typeColumn.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.HasThis, new[] { typeof(string) });
ILGenerator staticColumnConstructorILGenerator = staticColumnConstructorBuilder.GetILGenerator();
staticColumnConstructorILGenerator.Emit(OpCodes.Ldarg_0);
staticColumnConstructorILGenerator.Emit(OpCodes.Ldarg_1);
staticColumnConstructorILGenerator.Emit(OpCodes.Call, fieldBaseCtor);
staticColumnConstructorILGenerator.Emit(OpCodes.Nop);
staticColumnConstructorILGenerator.Emit(OpCodes.Nop);
staticColumnConstructorILGenerator.Emit(OpCodes.Ret);
var createdColumn = typeColumn.CreateType();
ConstructorInfo columnConstructor = createdColumn.GetConstructor(new[] { typeof(string) });
columnFields.Add(new ReflectionDefineField()
{
ConstructorInfo = columnConstructor,
Type = createdColumn
});
}
ConstructorBuilder staticTableConstructorBuilder =
typeTable.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.HasThis, Type.EmptyTypes);
ILGenerator staticTableConstructorILGenerator = staticTableConstructorBuilder.GetILGenerator();
staticTableConstructorILGenerator.Emit(OpCodes.Ldarg_0);
staticTableConstructorILGenerator.Emit(OpCodes.Call, tableBaseCtor);
// Initialise constructor of column classes and assign to property on table class
foreach (var field in columnFields)
{
FieldBuilder fieldColumn = typeTable.DefineField(field.ConstructorInfo.DeclaringType.Name, field.Type, FieldAttributes.InitOnly | FieldAttributes.Public);
staticTableConstructorILGenerator.Emit(OpCodes.Ldarg_0);
staticTableConstructorILGenerator.Emit(OpCodes.Ldstr, table.Name);
staticTableConstructorILGenerator.Emit(OpCodes.Newobj, field.ConstructorInfo);
staticTableConstructorILGenerator.Emit(OpCodes.Stfld, fieldColumn); // Stfld => non-static field!
}
staticTableConstructorILGenerator.Emit(OpCodes.Ret);
// Create the table class
var createdTable = typeTable.CreateType();
ConstructorInfo tableConstructor = createdTable.GetConstructor(Type.EmptyTypes);
tableFields.Add(new ReflectionDefineField()
{
ConstructorInfo = tableConstructor,
Type = createdTable
});
}
ConstructorBuilder staticDatabaseConstructorBuilder =
typeDatabaseModel.DefineConstructor(MethodAttributes.Private | MethodAttributes.PrivateScope | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Static, CallingConventions.Standard, Type.EmptyTypes);
ILGenerator staticDatabaseConstructorILGenerator = staticDatabaseConstructorBuilder.GetILGenerator();
// Initialise constructor of table classes and assign to property on mapping class
foreach (var field in tableFields)
{
FieldBuilder fieldDatabase = typeDatabaseModel.DefineField(field.ConstructorInfo.DeclaringType.Name, field.Type, FieldAttributes.InitOnly | FieldAttributes.Public | FieldAttributes.Static);
staticDatabaseConstructorILGenerator.Emit(OpCodes.Nop);
staticDatabaseConstructorILGenerator.Emit(OpCodes.Newobj, field.ConstructorInfo);
staticDatabaseConstructorILGenerator.Emit(OpCodes.Stsfld, fieldDatabase); // Stsfld => static field!
}
staticDatabaseConstructorILGenerator.Emit(OpCodes.Ret);
// Create the mapping class
var createdDatabaseModel = typeDatabaseModel.CreateType();
ab.Save(aName.Name + ".dll"); // Save .dll module
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment