Created
September 4, 2018 07:57
-
-
Save dalion619/86f4483130140bb62d90eeb009b423cb to your computer and use it in GitHub Desktop.
Create Dynamic Database Model Module
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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