I was busy to create architecture of asp.net (C#) project. In
the time of development, I faced a situation where it will be good to have a
dynamic property generation. I did some search, and found many examples. But
after going through all, I found something, which is really nice and solve my
problem. My problems are-
1> I need to get all the data fetched from
table in DB in a custom and pre-defined model in c#, but sometime DB queries
can return some columns which are not in the defined properties of predefined
model.
2> When I do serialization of the model
in c#, it should serialize in normal and proper way, with or without extra
columns returned from DB.
Example-
Suppose, I define a model –
Public class EmpModel{
Public string EmpName{get; set;}
Public string EmpId{get; set;}
}
And I also write three SQL queries-
SELECT EmpName,EmpId,EmpAddress from tbl_Employee
SELECT EmpName,EmpId,EmpDept from tbl_Employee
SELECT EmpName,EmpId,EmpDOB from tbl_Employee
Now, as you can see, the queries are returning
three columns, but the model only has two properties. I cannot manage EmpAddress,
EmpDept and EmpDOB in model. As well as, the 3rd field will be different
in type also. To manage this situation, I found-
1>
AssemblyBuilder
2>
ModuleBuilder
3>
TypeBuilder
4>
FieldBuilder
5>
PropertyBuilder
6>
MethodAttributes
7>
MethodBuilder
These are the main
building blocks of my solution.
The theory of the solution is, I have to create a class which will have EmpModel as
a base class and with the properties (Extra properties) needed. All these, need
to be done dynamically.
For all these,
I managed to write two method sets(Three methods), which will handle everything
for me-
MethodSet 1 (to bind DB columns with Model properties)-[Contains
two methods]
public void
getModelFromObject<T, T1>(object valu, ref List<T>
el,Dictionary<string,Type> props) where
T1 : T, new()
{
DataTable dt = ((DataSet)valu).Tables[0];
Type dynamicType = getType(typeof(T).Name+ "Ext",
props, typeof(T1));
foreach (DataRow
dr in ((DataSet)valu).Tables[0].Rows)
{
T item = (T)Activator.CreateInstance(dynamicType);
getObject<T>(dr, ref item, dt);
T tsts = item;
((List<T>)el).Add(item);
}
}
public void
getObject<T>(DataRow dr,ref T obj, DataTable
dt)
{
foreach (DataColumn
dc in dt.Columns)
{
if
(obj.GetType().GetProperty(dc.ColumnName) != null)
{
obj.GetType().GetProperty(dc.ColumnName).SetValue(obj,
dr[dc.ColumnName], null);
}
}
}
MethodSet 2(to create extended
properties)-[Contains one method]
public Type
getType(string dynamicClassName, Dictionary<string,
Type> propertyList, Type baseClassType)
{
bool isNewProperties = false;
AssemblyBuilder assemblyBilder = System.Threading.Thread.GetDomain().DefineDynamicAssembly
(new AssemblyName(dynamicClassName
+ "Assembly"), AssemblyBuilderAccess.Run);
ModuleBuilder moduleBilder =
assemblyBilder.DefineDynamicModule(dynamicClassName + "Module");
TypeBuilder typeBilder =
moduleBilder.DefineType(dynamicClassName, TypeAttributes.Public
| TypeAttributes.Class, baseClassType);
string propertyName = null;
Type propertyType = null;
var baseClassObj = Activator.CreateInstance(baseClassType);
foreach (var prop in propertyList)
{
propertyName = prop.Key;
propertyType = prop.Value;
var propExist =
baseClassObj.GetType().GetProperty(propertyName);
if
(propExist != null)
{
continue;
}
FieldBuilder filedBilder =
typeBilder.DefineField("_" +
propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBilder =
typeBilder.DefineProperty(propertyName, System.Reflection.PropertyAttributes.None, propertyType,
new Type[] {
propertyType });
MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig;
MethodBuilder currGetPropMthdBilder =
typeBilder.DefineMethod("geter",
GetSetAttr, propertyType, null);
ILGenerator currtGetIL =
currGetPropMthdBilder.GetILGenerator();
currtGetIL.Emit(OpCodes.Ldarg_0);
currtGetIL.Emit(OpCodes.Ldfld,
filedBilder);
currtGetIL.Emit(OpCodes.Ret);
MethodBuilder currSetPropMthdBilder =
typeBilder.DefineMethod("seter",
GetSetAttr, null, new
Type[] { propertyType });
ILGenerator currSetIL =
currSetPropMthdBilder.GetILGenerator();
currSetIL.Emit(OpCodes.Ldarg_0);
currSetIL.Emit(OpCodes.Ldarg_1);
currSetIL.Emit(OpCodes.Stfld,
filedBilder);
currSetIL.Emit(OpCodes.Ret);
propertyBilder.SetGetMethod(currGetPropMthdBilder);
propertyBilder.SetSetMethod(currSetPropMthdBilder);
isNewProperties = true;
}
if (isNewProperties == false)
{
return baseClassType;
}
return typeBilder.CreateType();
}
And now, the use of these methods-
List<IEmp>
obj = new List<IEmp>();
Dictionary<string,
Type> props= new
Dictionary<string,
Type>();
props.Add("EmpAddress", typeof(string));//if
more then one add more.
modelPlatform.init().getModelFromObject<IEmp,Emp>(ds,
ref obj, val);//ds- is the dataset returned from DB
return obj;
Same for two other queries also.
That’s it, Enjoy.