1/1页1 跳转到查看:3576
发新话题 回复该主题

把Sql数据转换为业务数据的几种方法

把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Ðçû

TOP

 

回复:把Sql数据转换为业务数据的几种方法

棒,经典ªCHí7^ö©zbbs.szblogs.comx=:†7Ðçû

TOP

 
1/1页1 跳转到
发表新主题 回复该主题