patterncsharpMinor
DAL mapping efficiency
Viewed 0 times
mappingefficiencydal
Problem
I am wondering if I can make these classes a bit more efficient.
Test Results
Single Run
secs
secs
10 Run Loop
secs
secs
100 Run Loop
secs
secs
All 3 attempts for both methods never peak over 25% CPU usage.
As you can see there really is no significant improvement over either method, and method 2 (judging by CPU usage) does not seem to multi-thread.
I am thinking that if I can get rid of my usage of reflection to map the columns to strongly-typed classes that it would make a significant boost to both methods performance, and I am sure that I can make improvements to the asyncronicity of method 2 as well... I just don't know how.
WrapperTest.cs
This is a continuati
Test Results
Single Run
- Method 1: 5 Columns - Text Query - 81178 Records = 00:00:00.6390366
secs
- Method 2: 5 Columns - Text Query - 81178 Records = 00:00:00.5360307
secs
10 Run Loop
- Method 1: 5 Columns - Text Query - 81178 Records = 00:00:05.3253045
secs
- Method 2: 5 Columns - Text Query - 81178 Records = 00:00:05.0912912
secs
100 Run Loop
- Method 1: 5 Columns - Text Query - 81178 Records = 00:00:54.1270959
secs
- Method 2: 5 Columns - Text Query - 81178 Records = 00:00:53.8710813
secs
All 3 attempts for both methods never peak over 25% CPU usage.
As you can see there really is no significant improvement over either method, and method 2 (judging by CPU usage) does not seem to multi-thread.
I am thinking that if I can get rid of my usage of reflection to map the columns to strongly-typed classes that it would make a significant boost to both methods performance, and I am sure that I can make improvements to the asyncronicity of method 2 as well... I just don't know how.
WrapperTest.cs
private static IList Map(DbDataReader dr) where T : new()
{
try
{
// initialize our returnable list
List list = new List();
// fire up the lamda mapping
var converter = new Converter();
// read in each row, and properly map it to our T object
var obj = converter.CreateItemFromRow(dr);
// reutrn it
return list;
}
catch (Exception ex)
{
// Catch an exception if any, an write it out to our logging mechanism, in addition to adding it our returnable message property
_Msg += "Wrapper.Map Exception: " + ex.Message;
ErrorReporting.WriteEm.WriteItem(ex, "o7th.Class.Library.Data.Wrapper.Map", _Msg);
// make sure this method returns a default List
return default(List);
}
}This is a continuati
Solution
Use LINQ expression compilation to generate mapping code at runtime. The concept is to generate a method that does
Test method with 80,000 x 100 iteration
Result:
Map function:
obj.Property1 = dataReader["Property1"]; ... dynamically.public class Converter where T : new()
{
private static ConcurrentDictionary _convertActionMap = new ConcurrentDictionary();
private Action _convertAction;
private static Action GetMapFunc()
{
var exps = new List();
var paramExp = Expression.Parameter(typeof(IDataReader), "dataReader");
var targetExp = Expression.Parameter(typeof(T), "target");
var getPropInfo = typeof(IDataRecord).GetProperty("Item", new[] { typeof(string) });
foreach (var property in typeof(T).GetProperties())
{
var getPropExp = Expression.MakeIndex(paramExp, getPropInfo, new[] { Expression.Constant(property.Name, typeof(string)) });
var castExp = Expression.TypeAs(getPropExp, property.PropertyType);
//var bindExp = Expression.Bind(property, castExp);
var bindExp = Expression.Assign(Expression.Property(targetExp, property), castExp);
exps.Add(bindExp);
}
return Expression.Lambda>(Expression.Block(exps), new[] { paramExp, targetExp }).Compile();
}
public Converter()
{
_convertAction = (Action)_convertActionMap.GetOrAdd(typeof(T), (t) => GetMapFunc());
}
public T CreateItemFromRow(IDataReader dataReader)
{
T result = new T();
_convertAction(dataReader, result);
return result;
}
}Test method with 80,000 x 100 iteration
static void Main(string[] args)
{
var dummyReader = new DummyDataReader();
var properties = typeof(DummyObject).GetProperties();
var startDate = DateTime.Now;
var converter = new Converter();
for (int i = 0; i (new DummyDataReader());
var obj = CreateItemFromRow(dummyReader, properties);
//var obj = converter.CreateItemFromRow(dummyReader);
dummyReader.DummyTail = i;
}
//var obj = CreateItemFromRow2(new DummyDataReader());
Console.WriteLine("Time used : " + (DateTime.Now - startDate).ToString());
Console.ReadLine();
}Result:
CreateItemFromRow : 18.5 seconds
Converter : 7.3 secondsMap function:
private static IList Map(DbDataReader dr) where T : new()
{
// initialize our returnable list
List list = new List();
// fire up the lamda mapping
var converter = new Converter();
while (dr.Read()) {
// read in each row, and properly map it to our T object
var obj = converter.CreateItemFromRow(dr);
list.Add(obj);
}
// reutrn it
return list;
}Code Snippets
public class Converter<T> where T : new()
{
private static ConcurrentDictionary<Type, object> _convertActionMap = new ConcurrentDictionary<Type, object>();
private Action<IDataReader, T> _convertAction;
private static Action<IDataReader, T> GetMapFunc()
{
var exps = new List<Expression>();
var paramExp = Expression.Parameter(typeof(IDataReader), "dataReader");
var targetExp = Expression.Parameter(typeof(T), "target");
var getPropInfo = typeof(IDataRecord).GetProperty("Item", new[] { typeof(string) });
foreach (var property in typeof(T).GetProperties())
{
var getPropExp = Expression.MakeIndex(paramExp, getPropInfo, new[] { Expression.Constant(property.Name, typeof(string)) });
var castExp = Expression.TypeAs(getPropExp, property.PropertyType);
//var bindExp = Expression.Bind(property, castExp);
var bindExp = Expression.Assign(Expression.Property(targetExp, property), castExp);
exps.Add(bindExp);
}
return Expression.Lambda<Action<IDataReader, T>>(Expression.Block(exps), new[] { paramExp, targetExp }).Compile();
}
public Converter()
{
_convertAction = (Action<IDataReader, T>)_convertActionMap.GetOrAdd(typeof(T), (t) => GetMapFunc());
}
public T CreateItemFromRow(IDataReader dataReader)
{
T result = new T();
_convertAction(dataReader, result);
return result;
}
}static void Main(string[] args)
{
var dummyReader = new DummyDataReader();
var properties = typeof(DummyObject).GetProperties();
var startDate = DateTime.Now;
var converter = new Converter<DummyObject>();
for (int i = 0; i < 80000 * 100; i++)
{
//var obj = CreateItemFromRow2<DummyObject>(new DummyDataReader());
var obj = CreateItemFromRow<DummyObject>(dummyReader, properties);
//var obj = converter.CreateItemFromRow(dummyReader);
dummyReader.DummyTail = i;
}
//var obj = CreateItemFromRow2<DummyObject>(new DummyDataReader());
Console.WriteLine("Time used : " + (DateTime.Now - startDate).ToString());
Console.ReadLine();
}CreateItemFromRow : 18.5 seconds
Converter<T> : 7.3 secondsprivate static IList<T> Map<T>(DbDataReader dr) where T : new()
{
// initialize our returnable list
List<T> list = new List<T>();
// fire up the lamda mapping
var converter = new Converter<T>();
while (dr.Read()) {
// read in each row, and properly map it to our T object
var obj = converter.CreateItemFromRow(dr);
list.Add(obj);
}
// reutrn it
return list;
}Context
StackExchange Code Review Q#33128, answer score: 3
Revisions (0)
No revisions yet.