Click here to Skip to main content
12,945,719 members (54,564 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as


1 bookmarked
Posted 24 Jun 2011

Object Relational Mapping via Reflection

, 15 Jul 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
Same thing 10-100 times faster.Additionally, IndexMap can be built only once per DataTable.using System;using System.Collections.Generic;using System.Data;using System.Linq;using System.Linq.Expressions;using System.Reflection;namespace ReflectiveReader{ public static...
Same thing 10-100 times faster.
Additionally, IndexMap can be built only once per DataTable.

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace ReflectiveReader
    public static class DataAccessExtensions
        //Getting Convert.ChangeType method's MethodInfo and store in static field to access later.
        private static readonly MethodInfo ChangeType =
                typeof(Convert).GetMethods(BindingFlags.Public | BindingFlags.Static)
                    .Where(m => m.Name == "ChangeType")
                    .Select(m => new { Method = m, Parameters = m.GetParameters() })
                    .Where(p => p.Parameters.Length == 2)
                    .Where(p => p.Parameters[0].ParameterType == typeof(Object) && p.Parameters[1].ParameterType == typeof(Type))
                    .Select(p => p.Method)
        /// <summary>
        /// Static class. Container for precompiled property-accessing delegates.
        /// </summary>
        /// <typeparam name="TReflectedType">Type, wich property-accessing delegates will be constructed on access to PropertySetters static property.</typeparam>
        private static class DataAccessExtensionReflectedType<TReflectedType> where TReflectedType : class
            private static Dictionary<string, Action<TReflectedType, object>> _setters = null;
            private static readonly object SyncRoot = new object();
            //Property implemented using singletone pattern. Simplifies debugging. (Comparing with .cctor initialization)
            public static IDictionary<string, Action<TReflectedType, object>> PropertySetters
                    if (_setters == null)
                        lock (SyncRoot)
                            if (_setters == null)
                            {//compile setters on first access
                                _setters = CompileSetters();
                    return _setters;
            /// <summary>
            /// Compiles delegates for setting properties of TReflectedType.
            /// </summary>
            /// <returns>Dictionary, contatning propertyname - delegate mapping.</returns>
            private static Dictionary<string, Action<TReflectedType, object>> CompileSetters()
                var setters = new Dictionary<string, Action<TReflectedType, object>>();
                var type = typeof(TReflectedType);
                var objectType = typeof(object);
                //for each property in TRefelectedType
                foreach (var property in type.GetProperties())
                    //that can be written
                    if (property.CanWrite)
                        var instance = Expression.Parameter(type, "instance");
                        var value = Expression.Parameter(objectType, "value");
                        //build lambda expression
                        var expression = Expression.Lambda(typeof(Action<TReflectedType, object>),
                                                                    Expression.TypeIs(value, typeof(DBNull))),
                                                                Expression.Property(instance, property),
                                                                        Expression.Call(null, ChangeType, value, Expression.Constant(property.PropertyType))
                                                           , instance , value);
                        //compile it into delegate
                        var @delegate = expression.Compile();
                        //store delegate into dictionary and associate with property's name
                        setters.Add(property.Name, (Action<TReflectedType, object>)@delegate);
                return setters;
        /// <summary>
        /// Builds Dictionary, associating column id in given DataTable with corresponding property-accessing delegate.
        /// </summary>
        /// <typeparam name="TInstanceType">Type of instance to write values to.</typeparam>
        /// <param name="table">DataTable to read values from.</param>
        /// <returns>Comumn id to property accessing delegate mapping.</returns>
        public static IDictionary<int, Action<TInstanceType, object>> BuildIndexMap<TInstanceType>(this DataTable table) where TInstanceType : class
            var indexMap = new Dictionary<int, Action<TInstanceType, object>>();
            //for each compiled property-accessing delegate and property name pair
            foreach (var pair in DataAccessExtensionReflectedType<TInstanceType>.PropertySetters)
                //get corresponding column index by property name
                var index = table.Columns.IndexOf(pair.Key);
                //if found
                if (index >= 0)
                    //add index and delegate to result dictionary
                    indexMap.Add(index, pair.Value);
            return indexMap;
        /// <summary>
        /// Sets properties of specified instance from given DataRow using given ColumnIndex to delegate mapping.
        /// </summary>
        /// <typeparam name="TInstanceType">Type of instance to set values.</typeparam>
        /// <param name="instance">Instance to set values.</param>
        /// <param name="indexMap">ColumnIndex to property-accessing delegate mapping.</param>
        /// <param name="row">Row to read values.</param>
        public static void SetPropertiesFrom<TInstanceType>(this TInstanceType instance, IDictionary<int, Action<TInstanceType, object>> indexMap, DataRow row) where TInstanceType : class
            foreach (var pair in indexMap)
                pair.Value(instance, row[pair.Key]);
        /// <summary>
        /// Sets properties of specified instance from given DataRow. Builds ColumnIndex to property-accessing delegate mapping and uses it.
        /// </summary>
        public static void SetPropertiesFrom<TInstanceType>(this TInstanceType instance, DataRow row) where TInstanceType : class
            SetPropertiesFrom(instance, BuildIndexMap<TInstanceType>(row.Table), row);


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


About the Author

Russian Federation Russian Federation
No Biography provided

You may also be interested in...


Comments and Discussions

QuestionHandling Nullables Pin
Jörgen Andersson5-Nov-12 2:52
memberJörgen Andersson5-Nov-12 2:52 
AnswerRe: Handling Nullables Pin
Kelqualyn5-Nov-12 7:20
memberKelqualyn5-Nov-12 7:20 
GeneralRe: Yep. Using CodeDom compiler for such task probably will resu... Pin
Kelqualyn19-Jul-11 21:45
memberKelqualyn19-Jul-11 21:45 
GeneralRe: Thanks heaps for updating the code, I understand what you ar... Pin
Simon Bridge19-Jul-11 17:56
memberSimon Bridge19-Jul-11 17:56 
GeneralTry to convert step-by-step instead of direct conversion. Ev... Pin
Kelqualyn4-Aug-11 9:56
memberKelqualyn4-Aug-11 9:56 
GeneralReal nice! I tried to implement type conversion to Enum type... Pin
simmerzeel3-Aug-11 4:20
membersimmerzeel3-Aug-11 4:20 
GeneralRe: Look at next post :-) Pin
Kelqualyn4-Aug-11 20:57
memberKelqualyn4-Aug-11 20:57 
Generaldeleted Pin
Kelqualyn14-Jul-11 20:48
memberKelqualyn14-Jul-11 20:48 
GeneralI really wanted to do a comparative test, running 1000 insta... Pin
Simon Bridge14-Jul-11 20:07
memberSimon Bridge14-Jul-11 20:07 
GeneralRe: To compile this code you need to target .NET Framework 4. Bu... Pin
Kelqualyn15-Jul-11 6:26
memberKelqualyn15-Jul-11 6:26 
GeneralReason for my vote of 3 This does not even compile... which ... Pin
Simon Bridge14-Jul-11 20:04
memberSimon Bridge14-Jul-11 20:04 

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.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.170518.1 | Last Updated 15 Jul 2011
Article Copyright 2011 by Kelqualyn
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid