Just Code‎ > ‎

C# - Fill DataTable using NBuilder.Net

posted Sep 30, 2015, 1:20 AM by Peter Henell   [ updated Sep 30, 2015, 1:21 AM ]
How do you easily generate some rows based on a given a set of Columns in a DataTable?
Each column of each row need to be of the correct datatype and each value of each row should be different.

This is one way to to it using NBuilder.
First define the columns in the DataTable somehow. 
--

var dt = new DataTable("Customer");
            dt.Columns.Add("ID", typeof(int));
            dt.Columns.Add("Name", typeof(string));
            dt.Columns.Add("BirthDate", typeof(DateTime));
--
Secondly, create a dynamic class - with one public property per column of the correct type in the datatable - which we can fill with data using NBuilder.
--

/// <summary>
    /// Based on
    /// http://stackoverflow.com/questions/3862226/dynamically-create-a-class-in-c-sharp
    /// </summary>
    public class DynamicTypeBuilder
    {
        private Type _createdType;

        public DynamicTypeBuilder(System.Data.DataTable schema)
        {
            this._createdType = CompileResultType(schema);
        }

        public dynamic CreateNewObject(System.Data.DataTable schema)
        {
            var entity = Activator.CreateInstance(_createdType);
            return entity;
        }

        public Type CompileResultType(System.Data.DataTable schema)
        {
            TypeBuilder tb = GetTypeBuilder(schema.TableName);
            
            ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public 
                | MethodAttributes.SpecialName 
                | MethodAttributes.RTSpecialName);

            foreach (System.Data.DataColumn field in schema.Columns)
                CreateProperty(tb, field.ColumnName, field.DataType);
            
            Type objectType = tb.CreateType();
            return objectType;
        }

        private TypeBuilder GetTypeBuilder(string typeSignature)
        {
            var an = new AssemblyName(typeSignature);
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
            TypeBuilder tb = moduleBuilder.DefineType(typeSignature
                                , TypeAttributes.Public |
                                TypeAttributes.Sealed |
                                TypeAttributes.Class |
                                TypeAttributes.AutoClass |
                                TypeAttributes.AnsiClass |
                                TypeAttributes.BeforeFieldInit |
                                TypeAttributes.AutoLayout
                                , null);
            return tb;
        }

        private void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
        {
            FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);

            PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
            MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName
                                                , MethodAttributes.Public | 
                                                  MethodAttributes.SpecialName | 
                                                  MethodAttributes.HideBySig
                                                , propertyType
                                                , Type.EmptyTypes);

            ILGenerator getIl = getPropMthdBldr.GetILGenerator();

            getIl.Emit(OpCodes.Ldarg_0);
            getIl.Emit(OpCodes.Ldfld, fieldBuilder);
            getIl.Emit(OpCodes.Ret);

            MethodBuilder setPropMthdBldr =
                tb.DefineMethod("set_" + propertyName,
                  MethodAttributes.Public |
                  MethodAttributes.SpecialName |
                  MethodAttributes.HideBySig,
                  null, new[] { propertyType });

            ILGenerator setIl = setPropMthdBldr.GetILGenerator();
            Label modifyProperty = setIl.DefineLabel();
            Label exitSet = setIl.DefineLabel();

            setIl.MarkLabel(modifyProperty);
            setIl.Emit(OpCodes.Ldarg_0);
            setIl.Emit(OpCodes.Ldarg_1);
            setIl.Emit(OpCodes.Stfld, fieldBuilder);

            setIl.Emit(OpCodes.Nop);
            setIl.MarkLabel(exitSet);
            setIl.Emit(OpCodes.Ret);

            propertyBuilder.SetGetMethod(getPropMthdBldr);
            propertyBuilder.SetSetMethod(setPropMthdBldr);
        }
    }
--
Thirdly, add the values generated into the table.
--

private static void Fill(DataTable schema, int rows)
        {
            var builder = new DynamicTypeBuilder(schema);

            var o = builder.CreateNewObject(schema);
            Type t = o.GetType();
            var entities = GetListOfGeneratedObjects(o, rows);
            foreach (var entity in entities)
            {
                var row = schema.NewRow();
                foreach (var prop in t.GetProperties())
                {
                    row[prop.Name] = t.GetProperty(prop.Name).GetValue(entity);
                }
                schema.Rows.Add(row);
            }
        }

        public static IList<T> GetListOfGeneratedObjects<T>(T objectTemplate, int rows)
        {
            return Builder<T>.CreateListOfSize(rows).Build();
        }

-
Complete Code:
--
class Program
    {
        static void Main(string[] args)
        {
            var dt = new DataTable("Customer");
            dt.Columns.Add("ID", typeof(int));
            dt.Columns.Add("Name", typeof(string));
            dt.Columns.Add("BirthDate", typeof(DateTime));

            Fill(dt, 100);
            foreach (DataRow row in dt.Rows)
            {
                foreach (DataColumn col in dt.Columns)
                {
                    Console.WriteLine(col.ColumnName + ":" + row[col]);
                }
            }
        }

        private static void Fill(DataTable schema, int rows)
        {
            var builder = new DynamicTypeBuilder(schema);

            var o = builder.CreateNewObject(schema);
            Type t = o.GetType();
            var entities = GetListOfGeneratedObjects(o, rows);
            foreach (var entity in entities)
            {
                var row = schema.NewRow();
                foreach (var prop in t.GetProperties())
                {
                    row[prop.Name] = t.GetProperty(prop.Name).GetValue(entity);
                }
                schema.Rows.Add(row);
            }
        }

        public static IList<T> GetListOfGeneratedObjects<T>(T objectTemplate, int rows)
        {
            return Builder<T>.CreateListOfSize(rows).Build();
        }
    }
/// <summary>
    /// Based on
    /// http://stackoverflow.com/questions/3862226/dynamically-create-a-class-in-c-sharp
    /// </summary>
    public class DynamicTypeBuilder
    {
        private Type _createdType;

        public DynamicTypeBuilder(System.Data.DataTable schema)
        {
            this._createdType = CompileResultType(schema);
        }

        public dynamic CreateNewObject(System.Data.DataTable schema)
        {
            var entity = Activator.CreateInstance(_createdType);
            return entity;
        }

        public Type CompileResultType(System.Data.DataTable schema)
        {
            TypeBuilder tb = GetTypeBuilder(schema.TableName);
            
            ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public 
                | MethodAttributes.SpecialName 
                | MethodAttributes.RTSpecialName);

            foreach (System.Data.DataColumn field in schema.Columns)
                CreateProperty(tb, field.ColumnName, field.DataType);
            
            Type objectType = tb.CreateType();
            return objectType;
        }

        private TypeBuilder GetTypeBuilder(string typeSignature)
        {
            var an = new AssemblyName(typeSignature);
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
            TypeBuilder tb = moduleBuilder.DefineType(typeSignature
                                , TypeAttributes.Public |
                                TypeAttributes.Sealed |
                                TypeAttributes.Class |
                                TypeAttributes.AutoClass |
                                TypeAttributes.AnsiClass |
                                TypeAttributes.BeforeFieldInit |
                                TypeAttributes.AutoLayout
                                , null);
            return tb;
        }

        private void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
        {
            FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);

            PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
            MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName
                                                , MethodAttributes.Public | 
                                                  MethodAttributes.SpecialName | 
                                                  MethodAttributes.HideBySig
                                                , propertyType
                                                , Type.EmptyTypes);

            ILGenerator getIl = getPropMthdBldr.GetILGenerator();

            getIl.Emit(OpCodes.Ldarg_0);
            getIl.Emit(OpCodes.Ldfld, fieldBuilder);
            getIl.Emit(OpCodes.Ret);

            MethodBuilder setPropMthdBldr =
                tb.DefineMethod("set_" + propertyName,
                  MethodAttributes.Public |
                  MethodAttributes.SpecialName |
                  MethodAttributes.HideBySig,
                  null, new[] { propertyType });

            ILGenerator setIl = setPropMthdBldr.GetILGenerator();
            Label modifyProperty = setIl.DefineLabel();
            Label exitSet = setIl.DefineLabel();

            setIl.MarkLabel(modifyProperty);
            setIl.Emit(OpCodes.Ldarg_0);
            setIl.Emit(OpCodes.Ldarg_1);
            setIl.Emit(OpCodes.Stfld, fieldBuilder);

            setIl.Emit(OpCodes.Nop);
            setIl.MarkLabel(exitSet);
            setIl.Emit(OpCodes.Ret);

            propertyBuilder.SetGetMethod(getPropMthdBldr);
            propertyBuilder.SetSetMethod(setPropMthdBldr);
        }
    }
Comments