Click here to Skip to main content
15,895,283 members
Articles / Programming Languages / C#

Converting a DataSet to a Generic List

Rate me:
Please Sign up or sign in to vote.
4.57/5 (6 votes)
18 Jul 2009CPOL7 min read 77.8K   993   25  
Presents a simple utility framework that helps in converting DataSets to generic Lists.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Collections;

namespace Citrus.Data.Core
{
    /// <summary>
    /// The implementation of the entity loader class
    /// </summary>
    public static class EntityLoader
    {
        /// <summary>
        /// Loads an entity list as inferred by the
        /// dataset provided
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataSet"></param>
        /// <returns></returns>
        public static List<T> Load<T>(DataSet dataSet)
        {
            List<T> entityList = new List<T>();
            FillEntityList(dataSet, 0, entityList);
            return entityList;
        }


        /// <summary>
        /// Fills an entity list provided
        /// </summary>
        /// <param name="dataSet">The dataset with the data</param>
        /// <param name="entityList">The entity list to populate</param>
        /// <returns></returns>
        static object FillEntityList(DataSet dataSet, int currentTable, object entityList)
        {
            // Generate the column map for the current table
            Type entityType = entityList.GetEntityTypeFromEntityList();

            Dictionary<Type, ColumnPropertyMap> entityColumnMaps = ColumnPropertyMap.CreateMapsForEntity(dataSet.Tables[currentTable], entityType);

            // For each row in the table, try to populate an entity
            for (int r = 0; r < dataSet.Tables[currentTable].Rows.Count; r++)
            {
                bool couldFillEntity = false;

                // Create an entity
                object entity = ObjectBuilder.Create(entityType);

                // Fill all non-entity properties in the entity with row columns
                couldFillEntity = FillEntity(dataSet, currentTable, r, entity, entityColumnMaps[entityType]);

                // Fill all the entity properties
                foreach (EntityPropertyInfo entityProperty in entity.GetEntityProperties())
                {
                    object containedEntity = ObjectBuilder.Create(entityProperty.PropertyInfo.PropertyType);
                    if (FillEntity(dataSet, currentTable, r, containedEntity, entityColumnMaps[entityProperty.PropertyInfo.PropertyType]))
                    {
                        if (entityProperty.PropertyAccess.CanWrite)
                        {
                            entityProperty.PropertyAccess.Set(entity, containedEntity);
                            couldFillEntity = true;
                        }
                    }
                }

                // Fill all the entity list properties
                foreach (EntityPropertyInfo entityListProperty in entity.GetEntityListProperties())
                {
                    // Get the specified data table for the curret entity list
                    int entityListTable = entityListProperty.DataTable == null ? currentTable : entityListProperty.DataTable.GetEffectiveDataTable(currentTable);

                    // If a data table index is explicitly specified load the data off of that
                    // In case we have an entity list but there is no table specified
                    // we can't do much.
                    if (entityListTable != currentTable)
                    {
                        // Load the entity list
                        object containedEntityList = ObjectBuilder.Create(entityListProperty.PropertyInfo.PropertyType);

                        // Fill it based on the table specified
                        FillEntityList(dataSet, entityListTable, containedEntityList);

                        // ... and finaly save it back
                        if (entityListProperty.PropertyAccess.CanWrite)
                            entityListProperty.PropertyAccess.Set(entity, containedEntityList);
                    }
                }

                if (couldFillEntity)
                    ((IList)entityList).Add(entity);
            }

            return entityList;
        }


        /// <summary>
        /// Fills an entity's basic properties
        /// </summary>
        /// <param name="dataSet"></param>
        /// <param name="whichTable"></param>
        /// <param name="whichRow"></param>
        /// <param name="entityType"></param>
        /// <param name="map"></param>
        /// <returns></returns>
        static bool FillEntity(DataSet dataSet, int currentTable, int whichRow, object entity, ColumnPropertyMap map)
        {
            bool couldFillEntity = false;

            DataRow currentRow = dataSet.Tables[currentTable].Rows[whichRow];

            // For every mapped column
            // set the value of the property
            foreach (var column in map.Keys)
            {
                if (!DBNull.Value.Equals(currentRow[column]))
                {
                    object valueToSet = currentRow[column];

                    // If a custom converter is specified
                    // use it to convert the data
                    if (null != map[column].DataConverter)
                        valueToSet = map[column].DataConverter.Converter.GetEntity(valueToSet);

                    if (map[column].PropertyAccess.CanWrite)
                    {
                        map[column].PropertyAccess.Set(entity, valueToSet);
                        couldFillEntity = true;
                    }
                }
            }

            // We return true if at least one basic
            // property was able to be filled
            return couldFillEntity;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Web Developer
United Kingdom United Kingdom
I work as a Technology Lead for an IT services company based in India.

Passions include programming methodologies, compiler theory, cartooning and calligraphy.

Comments and Discussions