最近连续看到几篇关于把DataRow映射为实体类的Helper
http://www.cnblogs.com/inday/archive/2008/12/23/1360495.html
http://www.cnblogs.com/yyliuliang/archive/2008/12/22/1358736.html
但是这2个helper都有不全,就是对NullAble和Enum都支持的不好。
如:以下的测试代码,对于Nullable类型,都不能通过测试,枚举类型
[Test]
public void T3()
{
var table = new DataTable("table");
table.Columns.Add(new DataColumn("s", typeof(string)));
table.Columns.Add(new DataColumn("i", typeof(string)));
table.Columns.Add(new DataColumn("b", typeof(string)));
DataRow row = table.NewRow();
row["s"] = "s";
row["i"] = "1";
row["b"] = "true";
var info = ModelHelper.ConvertModel<Model>(row);
Assert.IsNotNull(info);
Assert.AreEqual(info.B, true);
Assert.AreEqual(info.i, 1);
Assert.AreEqual(info.S, "s");
}
public class Model
{
public string S { get; set; }
public E1 E1 { get; set; }
public int? i { get; set; }
public bool B { get; set; }
}
public enum E1
{
a,
b,
c
}
我现在的MVC项目中的Helper也有DataRowToModel的代码,对Nullable和Enum实现了兼容。
主要代码为如下的转换代码(ps:这边分代码是更具MVC中的相关代码简化改进而来,MVC中还支持复杂类型)
Code
/// <summary>
/// Converts the type of the simple.
/// </summary>
/// <param name="culture">The culture.</param>
/// <param name="value">The value.</param>
/// <param name="destinationType">Type of the destination.</param>
/// <returns></returns>
public static object ConvertSimpleType(CultureInfo culture, object value, Type destinationType)
{
if (value == null || destinationType.IsInstanceOfType(value))
{
return value;
}
if (value == DBNull.Value)
{
return null;
}
// if this is a user-input value but the user didn't type anything, return no value
var valueAsString = value as string;
if (valueAsString != null && valueAsString.Length == 0)
{
return null;
}
TypeConverter converter = TypeDescriptor.GetConverter(destinationType);
if (destinationType.IsGenericType && destinationType.GetGenericTypeDefinition().Equals(typeof (Nullable<>))
&& value.GetType() != typeof (string))
{
var nulla = new NullableConverter(destinationType);
destinationType = nulla.UnderlyingType;
if (destinationType.IsEnum)
{
return Enum.ToObject(destinationType, value);
}
}
bool canConvertFrom = converter.CanConvertFrom(value.GetType());
if (!canConvertFrom)
{
converter = TypeDescriptor.GetConverter(value.GetType());
}
if (!(canConvertFrom || converter.CanConvertTo(destinationType)))
{
if (destinationType.IsEnum)
{
return Enum.ToObject(destinationType, value);
}
}
try
{
object convertedValue = (canConvertFrom)
? converter.ConvertFrom(null, culture, value)
: converter.ConvertTo(null, culture, value, destinationType);
return convertedValue;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
string message = String.Format(CultureInfo.CurrentUICulture, value.GetType().FullName,
destinationType.FullName);
throw new InvalidOperationException(message, ex);
}
}
下面是测试代码
Code
using System;
using System.Data;
using System.Diagnostics;
using NUnit.Framework;
namespace Helper
{
[TestFixture]
public class Test
{
[Test]
public void T1()
{
var table = new DataTable("table");
table.Columns.Add(new DataColumn("s", typeof (string)));
table.Columns.Add(new DataColumn("e1", typeof (string)));
table.Columns.Add(new DataColumn("e2", typeof(string)));
table.Columns.Add(new DataColumn("i1", typeof (string)));
table.Columns.Add(new DataColumn("i2", typeof(string)));
table.Columns.Add(new DataColumn("b1", typeof (string)));
table.Columns.Add(new DataColumn("b2", typeof(string)));
DataRow row = table.NewRow();
row["s"] = "s";
row["e1"] = "b";
row["e2"] = "c";
row["i1"] = "1";
row["i2"] = "2";
row["b1"] = "true";
row["b2"] = "true";
var info = ModelHelper.DataRowToModel<Model>(row);
Assert.IsNotNull(info);
Assert.AreEqual(info.B1, true);
Assert.AreEqual(info.B2, true);
Assert.AreEqual(info.E1, E1.b);
Assert.AreEqual(info.E2, E1.c);
Assert.AreEqual(info.i1, 1);
Assert.AreEqual(info.i2, 2);
Assert.AreEqual(info.S, "s");
row = table.NewRow();
row["s"] = "s";
row["e1"] = "1";
row["e2"] = "2";
row["i1"] = "1";
row["i2"] = "2";
row["b1"] = "true";
row["b2"] = "true";
info = ModelHelper.DataRowToModel<Model>(row);
Assert.IsNotNull(info);
Assert.AreEqual(info.B1, true);
Assert.AreEqual(info.B2, true);
Assert.AreEqual(info.E1, E1.b);
Assert.AreEqual(info.E2, E1.c);
Assert.AreEqual(info.i1, 1);
Assert.AreEqual(info.i2, 2);
Assert.AreEqual(info.S, "s");
}
[Test]
public void T2()
{
var table = new DataTable("table");
table.Columns.Add(new DataColumn("s", typeof (string)));
table.Columns.Add(new DataColumn("e1", typeof (int)));
table.Columns.Add(new DataColumn("e2", typeof(int)));
table.Columns.Add(new DataColumn("i1", typeof (int)));
table.Columns.Add(new DataColumn("i2", typeof(int)));
table.Columns.Add(new DataColumn("b1", typeof (bool)));
table.Columns.Add(new DataColumn("b2", typeof(bool)));
DataRow row = table.NewRow();
row["s"] = "s";
row["e1"] = 1;
row["e2"] = 2;
row["i1"] = 1;
row["i2"] = 2;
row["b1"] = "true";
row["b2"] = "true";
var info = ModelHelper.DataRowToModel<Model>(row);
Assert.IsNotNull(info);
Assert.AreEqual(info.B1, true);
Assert.AreEqual(info.E1, E1.b);
Assert.AreEqual(info.i1, 1);
Assert.AreEqual(info.S, "s");
}
[Test]
public void TestPerformance()
{
var table = new DataTable("table");
table.Columns.Add(new DataColumn("s", typeof (string)));
table.Columns.Add(new DataColumn("e1", typeof (int)));
table.Columns.Add(new DataColumn("i1", typeof (int)));
table.Columns.Add(new DataColumn("b", typeof (bool)));
DataRow row = table.NewRow();
row["s"] = "s";
row["e1"] = 1;
row["i1"] = 1;
row["b"] = true;
var timer = new Stopwatch();
timer.Start();
for (int i = 0; i < 1*10000; i++)
{
ModelHelper.DataRowToModel<Model>(row);
}
timer.Stop();
Console.WriteLine(timer.ElapsedMilliseconds + "\t");
var timer1 = new Stopwatch();
timer1.Start();
for (int i = 0; i < 1*10000; i++)
{
ModelHelper.FastDataRowToModel<Model>(row);
}
timer1.Stop();
Console.WriteLine(timer1.ElapsedMilliseconds + "\t");
}
}
public class Model
{
public string S { get; set; }
public E1 E1 { get; set; }
public E1? E2 { get; set; }
public int i1 { get; set; }
public int? i2 { get; set; }
public bool B1 { get; set; }
public bool? B2 { get; set; }
}
public enum E1
{
a,
b,
c
}
}
前2天刚好看到”时不我待“的
自己动手写个ORM实现(4) 关于反射DataRow数据记录到实体性能的优化
写这篇文章的时候顺便做了一下测试,比较一下lambda语法和反射的语法到底是否如”时不我待“说的那样有数量级上的区别
但是测试的结果确大大出乎意料,是数量级上的区别不过是相反的,反射时间远远小于lambad语法的时间
测试1W次,反射时间:197 lambad时间:5574
下面是我的测试代码
Code
[Test]
public void TestPerformance()
{
var table = new DataTable("table");
table.Columns.Add(new DataColumn("s", typeof (string)));
table.Columns.Add(new DataColumn("e1", typeof (int)));
table.Columns.Add(new DataColumn("i1", typeof (int)));
table.Columns.Add(new DataColumn("b", typeof (bool)));
DataRow row = table.NewRow();
row["s"] = "s";
row["e1"] = 1;
row["i1"] = 1;
row["b"] = true;
var timer = new Stopwatch();
timer.Start();
for (int i = 0; i < 1*10000; i++)
{
ModelHelper.DataRowToModel<Model>(row);
}
timer.Stop();
Console.WriteLine(timer.ElapsedMilliseconds + "\t");
var timer1 = new Stopwatch();
timer1.Start();
for (int i = 0; i < 1*10000; i++)
{
ModelHelper.FastDataRowToModel<Model>(row);
}
timer1.Stop();
Console.WriteLine(timer1.ElapsedMilliseconds + "\t");
}
}
下面是sln,包含class和测试
/Files/haptear/Helper.rar