Click here to Skip to main content
15,891,621 members
Articles / Programming Languages / C#

How To Convert a Generic List of Strong Typed Domain Object To Datatable

Rate me:
Please Sign up or sign in to vote.
4.16/5 (5 votes)
5 Jun 2009CPOL2 min read 32.1K   103   16   8
A useful sample of how to extend Generic List and convert it to a datatable

Introduction

Sometimes in business intelligence projects, programs have needs of converting domain objects in something manipulable using Datasets or DataView. Here is an example of how extension methods in C# 3.0 can help us do this work in very short classes.

Ok let's go, simply download the source code and try the example to see the magic.

I believe that this simple and short example should demonstrate how few lines of code can do big things! My own thoughts are that the software development should always be made by small methods and the classes must interact between themselves using abstract methods, virtualization extensions and so on. Naturally a correct architectural concern of the project is a must.

Using the Code

The code usage is very simple, and I provide a cut and paste of a unit test method of Visual Studio 2008 Team System that provides a sample of how you can use this piece of code:

[TestMethod]
public void costruzione_datatable_con_callback()
{
     var list = PivotTestData.GetMockAgents();
     Assert.IsNotNull(list);
     var i = 0;
     var table = list.ConvertDomainListToDataTable((agent => agent), 
					(s => (++i).ToString("n")));
     Assert.AreEqual(list.Count, table.Rows.Count);
}

And after the usage here is the source of the extension class that does the work. Please notice that this class uses two delegates expressed via lambda in the unit tests method that can transform the source object before the processing by the conversion Algorithm.

The first delegate (transformCallback) processes the entity transformation and the entity is passed after the callback in the unit test sample, the entity remains the same.

The second delegate (headerCallback) is used to populate the DataTable header and in the unit test sample, the field names are rebuilt with an int incremented.

C#
namespace Domain
{
    public abstract class DomainBase
    {

    }
        
    public class AgentAndSell: DomainBase
    {
        public string Name { get; set; }
        public double CashAmount { get; set; }
        public decimal Discount { get; set; }
        public DateTime OrderDate { get; set; }
    }
} 

For simplification in the unit test, I made a Mock of the list of the class AgentAndSell. Here is a simple example. In the source code, you can find a larger set.

C#
public static class PivotTestData
{
    public static IList<AgentAndSell> GetMockAgents()
    {
        IList<AgentAndSell> ret = new List<AgentAndSell>
           {
              new AgentAndSell { CashAmount = 10, Discount = 0, 
			Name ="Mario Rossi", OrderDate = new DateTime(2009,1,1)},
              new AgentAndSell { CashAmount = 10, Discount = 0, 
			Name ="Mario Rossi", OrderDate = new DateTime(2009,1,2)},
              new AgentAndSell { CashAmount = 10, Discount = 0, 
			Name ="Mario Rossi", OrderDate = new DateTime(2009,1,3)},
              new AgentAndSell { CashAmount = 10, Discount = 0, 
			Name ="Mario Rossi", OrderDate = new DateTime(2009,1,4)},
              new AgentAndSell { CashAmount = 10, Discount = 0, 
			Name ="Mario Rossi", OrderDate = new DateTime(2009,1,5)},
              new AgentAndSell { CashAmount = 10, Discount = 0, 
			Name ="Mario Rossi", OrderDate = new DateTime(2009,1,6)},
              new AgentAndSell { CashAmount = 10, Discount = 0, 
			Name ="Mario Rossi", OrderDate = new DateTime(2009,2,1)},
              new AgentAndSell { CashAmount = 10, Discount = 0, 
			Name ="Mario Rossi", OrderDate = new DateTime(2009,2,2)},
              new AgentAndSell { CashAmount = 10, Discount = 0, 
			Name ="Mario Rossi", OrderDate = new DateTime(2009,2,3)},
              new AgentAndSell { CashAmount = 10, Discount = 0, 
			Name ="Mario Rossi", OrderDate = new DateTime(2009,2,4)},
              new AgentAndSell { CashAmount = 10, Discount = 0, 
			Name ="Mario Rossi", OrderDate = new DateTime(2009,2,5)},
              new AgentAndSell { CashAmount = 10, Discount = 0, 
			Name ="Mario Rossi", OrderDate = new DateTime(2009,2,6)},
          };
        return ret;
    }
}
 
using System.Collections;
using System.Data;
using System.Collections.Generic;
using System.ComponentModel;
using System;
using Model;

namespace Extensions
{
    public static class DataTableExtensions
    {
        public static DataTable ConvertDomainListToDataTable<T>(
            this IList<T> list, Func<T, T> transformCallback, 
			Func<string, string> headerCallback)
            where T : DomainBase
        {
            var entityType = typeof(T);
            var table = entityType.BuildTableFromType(headerCallback);
            var properties = TypeDescriptor.GetProperties(entityType);
            foreach (var item in list)
            {
                var tableRow = table.NewRow();
                var item2 = transformCallback == null ? 
				item : transformCallback(item);
                if (transformCallback != null) item2 = transformCallback(item);
                var i = 0;
                foreach (PropertyDescriptor property in properties) 
				{ tableRow[i++] = property.GetValue(item2); }

                table.Rows.Add(tableRow);
            }   

            return table;
        }

        public static DataTable BuildTableFromType<T>
		(this T entityType, Func<string, string> headerCallback) 
            where T: Type
        {
            var table = new DataTable(entityType.Name);
            var properties = TypeDescriptor.GetProperties(entityType);
            foreach (PropertyDescriptor property in properties)
            {
                var headerItem = (headerCallback == null) ? 
			property.Name : headerCallback(property.Name);
                table.Columns.Add(headerItem, property.PropertyType);
            }

            return table;
        }
    }    
}

Points of Interest

In this example, the reader can easily learn something about expressions and lambda (features of C# 3.0) and also the PropertyDescriptor of the TypeDescription. Reflection should be used to reconstruct the entity back with the typeof(T) and the usage of the Activator class which can correctly instantiate our domain object.

That's all.

History

  • Ver. pre beta, this is a test but it works fine

Any suggestions and/or improvements are really appreciated.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Italy Italy
Hi.i.prefer not to tell so much about my biografy, i am an eternal student. Big Grin | :-D

Comments and Discussions

 
GeneralMy vote of 5 Pin
Kanasz Robert26-Sep-12 7:35
professionalKanasz Robert26-Sep-12 7:35 
GeneralVery good! Pin
Romulus Corneanu9-Jun-09 20:24
Romulus Corneanu9-Jun-09 20:24 
See also this MSDN article http://msdn.microsoft.com/en-us/library/bb669096.aspx[^].
GeneralRe: Very good! Pin
Emilio Reale10-Jun-09 2:49
Emilio Reale10-Jun-09 2:49 
GeneralRe: Very good! Pin
Emilio Reale10-Jun-09 3:22
Emilio Reale10-Jun-09 3:22 
GeneralCompare to Linq Pin
Member 12072698-Jun-09 17:07
Member 12072698-Jun-09 17:07 
QuestionIs this just one way? Pin
Dewey5-Jun-09 8:10
Dewey5-Jun-09 8:10 
AnswerRe: Is this just one way? Pin
Emilio Reale5-Jun-09 11:14
Emilio Reale5-Jun-09 11:14 
Generalthank you Pin
Egidio5-Jun-09 7:27
Egidio5-Jun-09 7:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.