Teddy's Knowledge Base

NBearMapping - 开源通用对象映射组件v1.0.0.2 beta - 支持枚举类型字段

NBearMapping是NBearV4框架的组件之一,可以独立使用。可用于任意类型对象、DataRow和DataReader对象间的透明映射。推荐结合NBearLite使用。

主要功能:

1、任意类型对象、DataRow和DataReader对象间的透明映射;
2、支持.NET的Nullable类型;
3、较高的性能,性能比基于Reflection的等价转换快约50%,手动代码 vs NBearMapping vs Reflection对象转换的执行时间比大约为1:2.5:3.6,可参见源码中MappingTest.TestPerformance() 测试;


源码、示例及文档下载:

NBearMapping_v1.0.0.2_beta.zip


使用演示:

 1        [TestMethod]
 2        public void TestDataRowToObject()
 3        {
 4            ObjectMapper mapper = new ObjectMapper(typeof(DataRow), typeof(User));
 5            mapper.AddCustomMappingName("UserID""ID");
 6            User user = (User)mapper.ConvertObject(table.Rows[0]);
 7            Assert.AreEqual(table.Rows[0]["UserID"], user.ID);
 8            Assert.AreEqual(table.Rows[0]["Name"], user.Name);
 9            User user2 = new User();
10            mapper.ConvertObject(table.Rows[0], user2);
11            Assert.AreEqual(table.Rows[0]["UserID"], user2.ID);
12            Assert.AreEqual(table.Rows[0]["Name"], user2.Name);   
13        }

14
15        [TestMethod]
16        public void TestDataReaderToObject()
17        {
18            ObjectMapper mapper = new ObjectMapper(typeof(IDataReader), typeof(User));
19            mapper.AddCustomMappingName("UserID""ID");
20            IDataReader reader = table.CreateDataReader();
21            reader.Read();
22            User user = (User)mapper.ConvertObject(reader);
23            Assert.AreEqual(table.Rows[0]["UserID"], user.ID);
24            Assert.AreEqual(table.Rows[0]["Name"], user.Name);
25            User user2 = new User();
26            IDataReader reader2 = table.CreateDataReader();
27            reader2.Read();
28            mapper.ConvertObject(reader2, user2);
29            Assert.AreEqual(table.Rows[0]["UserID"], user2.ID);
30            Assert.AreEqual(table.Rows[0]["Name"], user2.Name);        
31        }

32
33        [TestMethod]
34        public void ObjectToObject()
35        {
36            ObjectMapper mapper = new ObjectMapper(typeof(User), typeof(User));
37            User user = (User)mapper.ConvertObject(user3);
38            Assert.AreEqual(user3.ID, user.ID);
39            Assert.AreEqual(user3.Name, user.Name);
40            User user2 = new User();
41            mapper.ConvertObject(user3, user2);
42            Assert.AreEqual(user3.ID, user2.ID);
43            Assert.AreEqual(user3.Name, user2.Name);        
44        }

45
46        [TestMethod]
47        public void TestObjectToDataTableDataReaderAndDataRow()
48        {
49            ObjectMapper mapper = new ObjectMapper(typeof(User), typeof(DataTable));
50            mapper.AddCustomMappingName("ID""UserID");
51            DataTable userTable = (DataTable)mapper.ConvertObject(user3);
52            Assert.AreEqual(user3.ID, userTable.Rows[0]["UserID"== DBNull.Value ? null : userTable.Rows[0]["UserID"]);
53            Assert.AreEqual(user3.Name, userTable.Rows[0]["Name"]);
54            mapper.ConvertObject(user3, userTable);
55            Assert.AreEqual(user3.ID, userTable.Rows[1]["UserID"== DBNull.Value ? null : userTable.Rows[1]["UserID"]);
56            Assert.AreEqual(user3.Name, userTable.Rows[1]["Name"]);
57
58            mapper = new ObjectMapper(typeof(User), typeof(IDataReader));
59            mapper.AddCustomMappingName("ID""UserID");
60            IDataReader reader = (IDataReader)mapper.ConvertObject(user3);
61            Assert.IsNotNull(reader);
62
63            mapper = new ObjectMapper(typeof(User), typeof(DataRow));
64            mapper.AddCustomMappingName("ID""UserID");
65            DataRow row = (DataRow)mapper.ConvertObject(user3);
66            Assert.IsNotNull(row);
67        }


修订
7/26 更新至v1.0.0.1 修复1.0.0.0中的set null值的bug。

8/6 更新至v1.0.0.2 支持枚举类型字段

posted on 2007-07-25 15:23 Teddy's Knowledge Base 阅读(3841) 评论(17)  编辑 收藏 所属分类: Ent. App. Dev.NBear

评论

#1楼  2007-07-25 15:38 Nick.Lee      

同NickLee.Framework中的
NickLee.Common.ODRM理念差不多   回复  引用  查看    

#2楼  2007-07-25 16:04 icefire [未注册用户]

我刚学这个哪有视频文件可以下载看看!
谢谢
有的话把地址发到我邮箱
icefire2528@163.com   回复  引用    

#3楼  2007-07-25 17:29 申健      

个人感觉不是很喜欢NickLee,质量不是很高。   回复  引用  查看    

#4楼  2007-07-25 17:53 try      

刚测试了下NBearLite的写性能,不是很好,不太明白为什么.   回复  引用  查看    

#5楼 [楼主] 2007-07-25 17:55 Teddy's Knowledge Base      

@try
请问你是如何测试?“不是很好”又怎么具体解释呢?   回复  引用  查看    

#6楼  2007-07-25 18:10 try      

public long Execute(int repeatTimes)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Reset();
sw.Start();
for (int i = 0; i < repeatTimes; i++)
{
int catID = NBLiteHelper.db.Insert(Northwind.Categories)
.AddColumn(Northwind.Categories.CategoryName,"category1")
.AddColumn(Northwind.Categories.Description, "category1").ExecuteReturnAutoIncrementID(Northwind.Categories.CategoryID);

NBLiteHelper.db.Update(Northwind.Categories)
.AddColumn(Northwind.Categories.CategoryName, "testupdate")
.Where(Northwind.Categories.CategoryID == catID).Execute();

//---
..........
..........
..........
}
sw.Stop();
return sw.ElapsedMilliseconds;
}
是对比测试出的结果.
我新增了NBLite的测试.   回复  引用  查看    

#7楼  2007-07-25 20:42 yyb [未注册用户]

http://files.cnblogs.com/mail-ricklee/fortune.rar
http://files.cnblogs.com/mail-ricklee/dlllibrary2005.rar
这个里面用的IBatisNet也不错。   回复  引用    

#8楼  2007-07-25 21:12 Nick.Lee      

ODRM其中一个转换函数
/// <summary>
/// 数据集中一行DataRow转换为指定对象,并填充数据
/// </summary>
/// <param name="row">数据集中一行</param>
/// <param name="objModel">指定对象</param>
/// <returns>填充后对象</returns>
public static object DataTableConvertObject(DataRow row, object objModel)
{
//IDomain idomain = (IDomain)objModel;

//Hashtable hTable = new Hashtable();
//hTable = DataRowConvertHashtable(row);
//Type entitytype = Type.GetType(objModel.GetType().AssemblyQualifiedName);

//for (int j = 0; j < idomain.Propertylist.Length; j++)
//{
// PropertyInfo propertyinfo = entitytype.GetProperty(idomain.Propertylist[j]);
// try
// {
// propertyinfo.SetValue(objModel, hTable[idomain.Propertylist[j]], null);
// }
// catch (System.Exception e)
// {
// propertyinfo.SetValue(objModel, null, null);
// }
//}
//获取所有的属性Name
PropertyDescriptorCollection attCollection = TypeDescriptor.GetProperties(objModel);

Hashtable hTable = new Hashtable();
hTable = DataRowConvertHashtable(row);
Type entitytype = Type.GetType(objModel.GetType().AssemblyQualifiedName);

foreach (PropertyDescriptor attDescriptor in attCollection)
{
PropertyInfo propertyinfo = entitytype.GetProperty(attDescriptor.Name);
//propertyinfo.SetValue(objModel, (hTable[attDescriptor.Name] == DBNull.Value) ? null : obj1);
try
{
if (hTable[attDescriptor.Name]!=null)
{
object objValue=Convert.ChangeType(hTable[attDescriptor.Name],propertyinfo.PropertyType);
propertyinfo.SetValue(objModel, objValue, null);
}

}
catch (System.Exception e)
{
propertyinfo.SetValue(objModel, null, null);
}
}
return objModel;
}
调用方式
TestUser user=new TestUser ();
ODRM.DataTableConvertObject(DataTable.Row[1],user)
采用反射方式,同NBear相比来说,实现的代码有长有短,但都达到最终目的。

NBear方式
/// <summary>
/// Convert the specified inputObject to the output mapping type.
/// </summary>
/// <param name="inputObject">The inputObject must be consistent with the specified inputMappingType in ObjectMapper's Constructor.</param>
/// <param name="outputObject">outputObject is an instance to set member values on instead of create a new one.</param>
/// <returns></returns>
public object ConvertObject(object inputObject, object outputObject, params CustomObjectMemberMappingHandler[] customMappingHandlers)
{
Check.Require(inputObject != null, "inputObject could not be null.");

IMemberGetter getter = MemberGetterFactory.GetMemberGetter(inputType);
IMemberSetter setter = MemberSetterFactory.GetMemberSetter(outputType);
List<ObjectMember> getMembers = getter.GetMembers(inputObject);
Dictionary<string, ObjectMember> setMembers = new Dictionary<string, ObjectMember>();
for (int i = 0; i < getMembers.Count; ++i)
{
setMembers.Add(mappingNames.ContainsKey(getMembers[i].Name) ? mappingNames[getMembers[i].Name] : getMembers[i].Name, getMembers[i]);
}


if (typeof(DataRow) == outputType)
{
if (outputObject == null)
outputObject = ConstructDataTableSchema(inputType.Name, setMembers);
if (outputObject is DataTable)
{
DataTable table = outputObject as DataTable;
DataRow row = table.NewRow();
setter.SetMembers(row, setMembers);
table.Rows.Add(row);
table.AcceptChanges();
}
else
{
setter.SetMembers(outputObject, setMembers);
}
}
else
{
if (outputObject == null)
outputObject = Activator.CreateInstance(outputType);
setter.SetMembers(outputObject, setMembers);
}

if (realOutputType == typeof(IDataReader))
{
outputObject = (outputObject as DataTable).CreateDataReader();
}
else if (realOutputType == typeof(DataRow))
{
outputObject = (outputObject as DataTable).Rows[(outputObject as DataTable).Rows.Count - 1];
}

if (customMappingHandlers != null && customMappingHandlers.Length > 0)
{
for (int i = 0; i < customMappingHandlers.Length; ++i)
{
if (customMappingHandlers[i] != null)
customMappingHandlers[i](inputObject, outputObject);
}
}

return outputObject;
}
调用方式
User user2 = new User();
mapper.ConvertObject(table.Rows[0], user2);   回复  引用  查看    

#9楼 [楼主] 2007-07-25 21:16 Teddy's Knowledge Base      

@Nick.Lee
单纯的DataRow转换Entity没什么大不了的。NBearMapping的优势在于任意对象Mapping,DataRow转Entity这里只是一种特例,重要的是任意的Object转Object。   回复  引用  查看    

#10楼  2007-07-25 21:55 @源 [未注册用户]

新东西来的真快,我刚准备在我的一个较大规模项目(ERP项目)中使用NBear,但目前又开始出新版本了,不知新版本与3.7的版本能兼容不?又让我开始犹豫了。   回复  引用    

#11楼  2007-07-30 09:37 tester [未注册用户]

object2object!太好了!有了这个就可以充分利用orm的优势了,比如说将object2Table这样的转换可以么?或者table2object?   回复  引用    

#12楼  2007-08-23 12:57 Evernory      

好东西啊~~向高手学习。   回复  引用  查看    

#13楼  2007-08-31 13:13 边城浪 [未注册用户]

测试方法不太准确....对没有使用缓存,对基于Reflection的测试不公平
.我认为改为这样才公道....
这样测下来的结果 NBearMapping 和 Reflection 大致一样...
[TestMethod]
public void TestPerformance()
{
int rowCount = 10000;

DataTable userTable = (DataTable)table.Clone();
for (int i = 0; i < rowCount; ++i)
{
userTable.Merge(table, true);
}

Console.WriteLine(string.Format("Test performance of converting {0} data rows to class objects", rowCount));
Console.WriteLine("Manually Coding vs NBearMapping vs Reflection");

//manually coding
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
User[] users1 = new User[userTable.Rows.Count];
for (int i = 0; i < userTable.Rows.Count; ++i)
{
users1[i] = new User((int)userTable.Rows[i]["UserID"], (string)userTable.Rows[i]["Name"], (UserStatus)userTable.Rows[i]["Status"]);
}
watch.Stop();
long ticks1 = watch.ElapsedTicks;
Console.WriteLine(string.Format("{0} (1)", ticks1));
Console.WriteLine(" vs ");

//NBearMapping
ObjectMapper mapper = new ObjectMapper(typeof(DataRow), typeof(User));
mapper.AddCustomMappingName("UserID", "ID");
User temp = (User)mapper.ConvertObject(userTable.Rows[0], new User());
Assert.AreEqual(userTable.Rows[0]["UserID"], temp.ID);
Assert.AreEqual(userTable.Rows[0]["Name"], temp.Name);
Assert.AreEqual(userTable.Rows[0]["Status"], (int)temp.Status);
watch.Reset();
watch.Start();
User[] users2 = new User[userTable.Rows.Count];
for (int i = 0; i < userTable.Rows.Count; ++i)
{
users2[i] = (User)mapper.ConvertObject(userTable.Rows[i], new User());
}
watch.Stop();
long ticks2 = watch.ElapsedTicks;
Console.WriteLine(string.Format("{0} ({1})", ticks2, ticks2*1.0/ticks1));
Console.WriteLine(" vs ");

//reflection
watch.Reset();
watch.Start();
User[] users3 = new User[userTable.Rows.Count];

System.Reflection.PropertyInfo pid = typeof(User).GetProperty("ID");
System.Reflection.FieldInfo pname = typeof(User).GetField("Name");
System.Reflection.FieldInfo fStatus = typeof(User).GetField("Status");

for (int i = 0; i < userTable.Rows.Count; ++i)
{
User newUser = new User();
pid.SetValue(newUser, userTable.Rows[i]["UserID"], null);
pname.SetValue(newUser, userTable.Rows[i]["Name"]);
fStatus.SetValue(newUser, (UserStatus)userTable.Rows[i]["Status"]);
users3[i] = newUser;
}
watch.Stop();
long ticks3 = watch.ElapsedTicks;
Console.WriteLine(string.Format("{0} ({1})", ticks3, ticks3*1.0/ticks1));
}   回复  引用    

#14楼  2007-11-03 17:44 CornyCN [未注册用户]

能否提两个建议

1.在使用NBearMapping进行Mapper的时候,是否可以指定排除的属性,我想之报以在V4中使用新的Mapper,就是因为我们的Entity往往不会与数据库Table完全一致,有时候甚至相差很大,全面枚举Entity属性,并且从Table或其他数据集对象中去检索,不仅是效率问题,而且容易让我们混淆Code错误与是否不需要Mapper的区别,若能指定在Mapper的时候排除的属性,将会更为简单,Mapper的过程也不需要那么复杂了吧,这个应该可以通过Attribute来实现的。

2.在NBearLite的Database构造函数中,使用一个string参数类型时,它使用的是Config文件中的ConnectionStringName,但实际使用中,我们往往需要对Connectionstring加密,因此不大可能直接将这个ConnectionStringName交给NBearLite去使用,因此交给 NBearLuite的应该是一个ConnectionString,但此时我们又不得不选择DatabaseType或是Provider,我们知道Provider可以写在ConnectionString中,也就是DatabaseType在这里进行选择其实某种程度看只是为了区别于ConnectionStringName的签名,我想是不是可以再考虑一下这个签名问题。我想说的是,所有数据库连接参数都可以写在ConnectionString中,这个连接串我们通过加密写在Config文件中,使用NBearLite带来的好处之一是避开直接与数据库的关系,也就是说,若能避开选择DatabaseType或是Provider,我们编辑后的数据层将可以不经修改的访问不同的后台数据,如SQL Server或是Oracle,不知道我说的正确不正确,但我觉得你可以考虑一下这个问题。   回复  引用    


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-01-23 21:44 编辑过


相关链接: