登录
注册
标签
会员
搜索
帮助
深圳博客技术论坛
»
【编程讨论学习】
»
『ADO.NET数据库技术』
»
把Sql数据转换为业务数据的几种方法
帖子标题
【编程讨论学习】
『
Winson.Framework
』
『ASP.NET程序设计』
『C#技术』
『VB.NET技术』
『ADO.NET数据库技术』
『Javascript/Ajax技术』
『HTML/CSS技术』
『Discuz! NT相关技术』
【闲聊区】
〖心得体会〗
〖闲话家常〗
〖广而告知〗
【站务区】
『最新公告』
『站务管理』
1/1页
1
跳转到
页
查看:3576
把Sql数据转换为业务数据的几种方法
winson
winson
组别:
管理员
性别:
积分:968
帖子:762
2007-07-29 13:11
| 只看楼主
树型
|
收藏
|
小
中
大
1
#
把Sql数据转换为业务数据的几种方法
ORM系统必须把数据库中的数据转换为业务数据,转换的方法大致有3种,本文就试图对它们做一些简单分析。
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
1、属性反射
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
就是通过反射,获取业务实体类的各个属性,然后再设置这些属性的值。这个方法最简单、最稳定、通用性最强、可维护性最强、性能最差。例如NHibernate就是用这种方法实现的,它通过IGetter和ISetter接口实现对某个业务实体类属性的读取和写入。DongLiORM的早期版本也是用的这种方法,他通过BusinessObject的属性索引器实现。其原理就是首先通过获取某个业务实体类某个属性的PropertyInfo,然后调用该PropertyInfo的GetValue或者SetValue方法。类似的代码如下:
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
PropertyInfo info
=
BusinessType.GetProperty(PropertyName);
info.SetValue(
this
, value,
null
);
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
比如,现在有一个业务实体类UserItem,其定义如下:
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
public
class
UserItem
...
{
public
UserItem()
...
{ }
private
string
_userid;
private
string
_username;
private
string
_pwd;
private
string
_email;
public
string
UserID
...
{
set
...
{ _userid
=
value; }
get
...
{
return
_userid; }
}
public
string
UserName
...
{
set
...
{ _username
=
value; }
get
...
{
return
_username; }
}
public
string
Pwd
...
{
set
...
{ _pwd
=
value; }
get
...
{
return
_pwd; }
}
public
string
Email
...
{
set
...
{ _email
=
value; }
get
...
{
return
_email; }
}
}
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
UserItem对应数据库中的Users表,他的属性对应Users表的字段UserID,UserName,Pwd,Email。现有一个返回了Users表数据的IDataReader,要把IDataReader转换为一个UserItem的数组,就用类似如下的方法:
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
public
T[] DbReaderToBusinessObject
<
T
>
(IDataReader Reader)
where
T :
new
()
...
{
List
<
T
>
list
=
new
List
<
T
>
();
while
(Reader.Read())
...
{
T Item
=
new
T();
Type BusinessType
=
Item.GetType();
for
(
int
i
=
0
; i
<
Reader.FieldCount; i
++
)
...
{
string
PropertyName
=
Reader.GetName(i);
PropertyInfo info
=
BusinessType.GetProperty(PropertyName);
info.SetValue(Item, Reader
,
null
);
}
list.Add(Item);
}
Reader.Close();
return
list.ToArray();
}
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
2、通过XML序列化。
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
就是在读取数据的时候,从数据库中返回的Xml形式的数据,然后通过用XmlSerializer的Deserialize方法把数据转换成业务数据。目前没有见到有用这种方法实现的产品。其优点同第一种方法,但转换的效率似乎比第一种方法效率高一些(不过也不会高多少,反序列化实际上也需要反射),但是增加了从数据库中返回数据的数据量,而且对于已经编译了的业务实体类也无能为力。其实现方法类似下面的过程(以Sql Server 2000为例)。
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
业务实体类的定义:
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
[Serializable]
[XmlRoot(
"
Users
"
)]
public
class
UserItem
...
{
public
UserItem()
...
{ }
private
string
_userid;
private
string
_username;
private
string
_pwd;
private
string
_email;
[XmlAttribute(
"
UserID
"
)]
public
string
UserID
...
{
set
...
{ _userid
=
value; }
get
...
{
return
_userid; }
}
[XmlAttribute(
"
UserName
"
)]
public
string
UserName
...
{
set
...
{ _username
=
value; }
get
...
{
return
_username; }
}
[XmlAttribute(
"
Pwd
"
)]
public
string
Pwd
...
{
set
...
{ _pwd
=
value; }
get
...
{
return
_pwd; }
}
[XmlAttribute(
"
Email
"
)]
public
string
Email
...
{
set
...
{ _email
=
value; }
get
...
{
return
_email; }
}
}
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
转换过程:
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
List
<
UserItem
>
UserList
=
new
List
<
UserItem
>
();
string
XmlSql
=
"
select * from Users for xml auto
"
;
SqlCommand cmd
=
new
SqlCommand(XmlSql, con);
cmd.CommandText
=
XmlSql;
XmlReader r
=
cmd.ExecuteXmlReader();
XmlSerializer sr
=
new
XmlSerializer(
typeof
(UserItem));
while
(r.Read())
...
{
UserList.Add(sr.Deserialize(r)
as
UserItem);
}
r.Close();
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
3、在业务实体类中自定义一个把Sql数据解析成业务数据的方法。
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
这种方法的优点是转换的效率非常高,在理想的情况下,和Ado.net的速度不相上下,缺点是必须对每个业务实体类实现一个把Sql数据解析成业务数据的方法。手工编码的工作量非常大,配上专门的代码辅助工具,可以减轻工作量,但是,如果数据结构需要改动,则改动的地方比较多,容易出错。用这种方法实现的有NBear V3,DongLiORM 1.2等。比如NBear V3中就有几个专门方法,比如:
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
public
override
void
SetPropertyValues(System.Data.IDataReader reader);
public
override
void
SetPropertyValues(System.Data.DataRow row);
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
而DongLiORM则是通过重写索引器(还是上文的UserItem):
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
public
override
object
this
[
string
PropertyName]
...
{
get
...
{
switch
(PropertyName)
...
{
case
"
UserID
"
br>
return
_userid;
case
"
UserName
"
br>
return
_username;
case
"
Pwd
"
br>
return
_pwd;
case
"
Email
"
br>
return
_email;
}
return
base
[PropertyName];
}
set
...
{
switch
(PropertyName)
...
{
case
"
UserID
"
br>
_userid
=
(
string
) value;
return
;
case
"
UserName
"
:
_username
=
(
string
) value;
return
;
case
"
Pwd
"
:
_pwd
=
(
string
) value;
return
;
case
"
Email
"
:
_email
=
(
string
) value;
return
;
}
base
[PropertyName]
=
value;
}
}
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
“鱼我所欲也,熊掌亦我所欲也,二者不可得兼,舍鱼而取熊掌者也”。系统的性能和代码简单性,二者不可兼得,到底我们更需要谁呢?
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
狂想:假设我们有一个这样的东西,他能够在运行时候改变现有的某个类(比如UserItem)的某个属性(比如索引器)/方法(比如SetPropertyValues)就好了,这样我们就可以在设计的时候写非常少的代码,而又能够获得比较高的运行效率。可惜PropertyBuilder等只能对动态类有用,帮不上忙。
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
我所想到方法的就这些,各有优点和缺点,不知各位有没有其他的方法,能让统的性能和代码简单性和谐统一。
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
随风飘飘天地任逍遥!
http://winson.szblogs.com
http://winsonet.cnblogs.com
TOP
发送短消息
查看公共资料
查找该会员全部帖子
UID:1
精华:
22
威望:96 点
金钱:488.45 博币
来自:深圳
注册: 2007-07-14
状态:
离线
rainbow
组别:兴趣学员
性别:
积分:4
帖子:4
2007-08-25 21:56
树型
|
收藏
|
小
中
大
2
#
回复:把Sql数据转换为业务数据的几种方法
棒,经典
ªCHí7^ö©zbbs.szblogs.comx=:7Ðçû
TOP
发送短消息
查看公共资料
查找该会员全部帖子
UID:232
精华: 0
威望:0 点
金钱:0.4 博币
来自:
注册: 2007-08-25
状态:
离线
<<
上一主题
|
下一主题
>>
1/1页
1
跳转到
页
发新主题
论坛跳转...
【编程讨论学习】
『
Winson.Framework
』
『ASP.NET程序设计』
『C#技术』
『VB.NET技术』
『ADO.NET数据库技术』
『Javascript/Ajax技术』
『HTML/CSS技术』
『Discuz! NT相关技术』
〖插件模板〗
【闲聊区】
〖心得体会〗
〖闲话家常〗
〖广而告知〗
【站务区】
『最新公告』
『站务管理』
基本状况
流量统计
客户软件
发帖量记录
版块排行
主题排行
发帖排行
积分排行
在线时间
我的主题
我的帖子
我的精华
我的附件
我的资料
帖子标题
作 者