惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 永红

东莞依时利诚聘java与.net方面的英才 项目管理笔记(观念) 项目管理笔记(概述) 【置顶】DLPrinter WEB打印组件第2次更新 也谈WEB打印(五):在IE的打印预览窗口中定义自己的用户接口 也谈WEB打印(四):让我们的模板支持打印,并根据内容动态的生成页面 也谈WEB打印(三):抛开IE,实现我们自己的打印模板 也谈WEB打印(二):简单的分析一下IE的打印原理并实现简单的打印和预览 也谈WEB打印(-):目前的几种方式及我们的任务 整理的几个常用的数据库维护的脚本 揭秘SQL Server 2000中的Bookmark Lookup 用MSIL剥开C#的外衣(一):方法参数ref、out、params和lock、for和foreach关键字 【翻译】MSIL 教程(三):类和异常处理 【翻译】MSIL 教程(二):数组、分支、循环、使用不安全代码和如何调用Win32 API 【翻译】MSIL 教程(一) 设计模式实战:用Prototype模式提高系统的开发效率,用DynamicMethod、Flyweight模式提高系统的运行效率 用DynamicMethod提升ORM系统转换业务数据的性能 设计模式实战:在WinForm中用Command模式实现可以撤销的数据操作 设计模式实战:组合型模式Composite,Adapter
把Sql数据转换为业务数据的几种方法
永红 · 2007-07-27 · via 博客园 - 永红

ORM系统必须把数据库中的数据转换为业务数据,转换的方法大致有3种,本文就试图对它们做一些简单分析。

1、属性反射。就是通过反射,获取业务实体类的各个属性,然后再设置这些属性的值。这个方法最简单、最稳定、通用性最强、可维护性最强、性能最差。例如NHibernate就是用这种方法实现的,它通过IGetterISetter接口实现对某个业务实体类属性的读取和写入。DongLiORM的早期版本也是用的这种方法,他通过BusinessObject的属性索引器实现。其原理就是首先通过获取某个业务实体类某个属性的PropertyInfo,然后调用该PropertyInfoGetValue或者SetValue方法。类似的代码如下:

PropertyInfo info = BusinessType.GetProperty(PropertyName);

info.SetValue(this, value, null);

比如,现在有一个业务实体类UserItem,其定义如下:

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; }

   }

}

UserItem对应数据库中的Users表,他的属性对应Users表的字段UserIDUserNamePwdEmail。现有一个返回了Users表数据的IDataReader,要把IDataReader转换为一个UserItem的数组,就用类似如下的方法:

        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[i],null);

                }

                list.Add(Item);

            }

            Reader.Close();

            return list.ToArray();

  }

2、通过XML序列化。就是在读取数据的时候,从数据库中返回的Xml形式的数据,然后通过用XmlSerializerDeserialize方法把数据转换成业务数据。目前没有见到有用这种方法实现的产品。其优点同第一种方法,但转换的效率似乎比第一种方法效率高一些(不过也不会高多少,反序列化实际上也需要反射),但是增加了从数据库中返回数据的数据量,而且对于已经编译了的业务实体类也无能为力。其实现方法类似下面的过程(以Sql Server 2000为例)。

   业务实体类的定义:

   [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; }

        }

   }

   转换过程:

   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();

3、在业务实体类中自定义一个把Sql数据解析成业务数据的方法。这种方法的优点是转换的效率非常高,在理想的情况下,和Ado.net的速度不相上下,缺点是必须对每个业务实体类实现一个把Sql数据解析成业务数据的方法。手工编码的工作量非常大,配上专门的代码辅助工具,可以减轻工作量,但是,如果数据结构需要改动,则改动的地方比较多,容易出错。用这种方法实现的有NBear V3DongLiORM 1.2等。比如NBear V3中就有几个专门方法,比如:

public override void SetPropertyValues(System.Data.IDataReader reader);

public override void SetPropertyValues(System.Data.DataRow row);

DongLiORM则是通过重写索引器(还是上文的UserItem)

public override object this[string PropertyName]

     {

            get

            {

                switch (PropertyName)

                {

                    case "UserID": return _userid;

                    case "UserName": return _username;

                    case "Pwd": return _pwd;

                    case "Email": return _email;

                }

                return base[PropertyName];

            }

            set

            {

                switch (PropertyName)

                {

                    case "UserID": _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;

            }

}

“鱼我所欲也,熊掌亦我所欲也,二者不可得兼,舍鱼而取熊掌者也”。系统的性能和代码简单性,二者不可兼得,到底我们更需要谁呢?

狂想:假设我们有一个这样的东西,他能够在运行时候改变现有的某个类(比如UserItem)的某个属性(比如索引器)/方法(比如SetPropertyValues)就好了,这样我们就可以在设计的时候写非常少的代码,而又能够获得比较高的运行效率。可惜PropertyBuilder等只能对动态类有用,帮不上忙。

我所想到方法的就这些,各有优点和缺点,不知各位有没有其他的方法,能让统的性能和代码简单性和谐统一。