5.数据库:ORM

来源:互联网 发布:淘宝绸缎丝带 编辑:程序博客网 时间:2024/05/16 05:54

第一部分:

本文来自:http://blog.csdn.net/sgear/article/details/7408251

题记:今天同事提到ORM。。。。就说说它吧。。。

1.什么是ORM?

  ORM,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作对象的属性和方法。

2.Snake.NET中ORM的特点与概述:

  Snake.Net框架是基于.Net的应用而设计的,它和其他一些移植于Java的ORM应用构架不同,是完全根据.Net的特点设计和开发。

Snake.Net框架使用一个完整的DataSet构架(见图2-1-1),用以描述一个应用项目所涉及的数据结构(包括可描述性的表结构、关键字、外部关键字以及表与表之间的关系等)。并使用特定的方法,将DataSet构架内所描述的数据表、数据列、关键字、表之间的关联关系与具体的业务实体对象进行映射,并实现业务实体对象的数据访问。  

3.数据库联接的设置:
  ORM系统是与数据库进行交互操作,和数据库的连接就成为最首要的话题。Snake.Net框架支持业务实体对一个或多个不同类型的数据库的访问支持,在框架内可以使用两种方法设置数据库连接:使用配置文件和运行时设置。

Snake.Net允许在一个系统中可以同时使用多个数据库配置。同时提供了对不同种类的数据库具有广乏的支持,几乎可以使用当前所有主流的数据库产品。

优势:ORM自其概念被提出,就得到了无数的响应,花样繁多的应用框架更是应接不暇。可见,他是有其独到的优势的。那么他的优势有哪些那:

第一,ORM最大的优势就是隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得我们的通用数据库交互变得简单易行,并且完全不用考虑该死的SQL语句。快速开发,由此而来。

第二:ORM使我们构造固化数据结构变得简单易行。
   在ORM年表的史前时代,我们需要将我们的对象模型转化为一条一条的SQL语句,通过直连或是DB helper在关系数据库构造我们的数据库体系。而现在,基本上所有的ORM框架都提供了通过对象模型构造关系数据库结构的功能。这,相当不错。


缺点:
第一:无可避免的,自动化意味着映射和关联管理,代价是牺牲性能(早期,这是所有不喜欢ORM人的共同点)。现在的各种ORM框架都在尝试使用各种方法来减轻这块(LazyLoad,Cache),效果还是很显著的。

第二:面向对象的查询语言(X-QL)作为一种数据库与对象之间的过渡,虽然隐藏了数据层面的业务抽象,但并不能完全的屏蔽掉数据库层的设计,并且无疑将增加学习成本.


第三: 对于复杂查询,ORM仍然力不从心。虽然可以实现,但是不值的。视图可以解决大部分calculated column,case ,group,having,order by, exists,但是查询条件(a and b and not c and (d or d))。。。。。。

        世上没有驴是不吃草的(又想好又想巧,买个老驴不吃草),任何优势的背后都隐藏着缺点,这是不可避免的。问题在于,我们是否能容忍缺点。ADA代码虽然易用性很差,但是US.DoD(the department of defense)欣赏他的运算速度;.net平台很不错,但是他是MS的。^_^

 ORM为何而生

  在数月以前,我有幸参加了一个公司内部的组件发布会。令我深感意外的事,一向无人关心的组件发布会这次变得人山人海,在漫长的新版本介绍之后。每个开发组长都跳出来抱怨上一个版本的问题,并且宣布与刚发布的新版本也是无法满足他们的需要的。一切都是如此的混乱,以至领导层不得不采用镇压的方式来平息怒火冲天的人们。
  在会后的那个晚上,我仔细回想了这次冲突。因为据我了解,这一系列的组件非常完美的完成了他所被期待的功能。可是为什么还是会被抱怨如此那。我觉得,可能,他(组件)是没有被正确使用了。

不知道还有谁记得James Elliott的那句话,

As good object-oriented developers got tired of this repetitive work, their typical tendency towards enlightened laziness started to manifest itself in the creation of tools to help automate the process. When working with relational databases, the culmination of such efforts were object/relational mapping tools.

  ORM构架只能是一个helper,他定位与此,而不是完整的数据持久层。他的设计者从来就没把他定位于取代一切的超级美女。ORM致力为长久以来的程序员与”重复劳动”的战争而助拳。与任何一个helper一样,他有自己的不足,他有优点也有缺点。
  无数的开发人员试图将使用ORM的框架构架自己项目的数据持久层,很多人感受到了ORM的优势,他们欢心鼓舞。但是很不幸,也有很多人失败或是深受蹉责。
  还有许多人,无奈的编写着很多ORM不适合作的事情。其实想一想,被自己舍弃了的以前的helper工具,难道真的一无是处了?

ORM与DB Helper Library:
  很多人可能都接触过这类的helper,每个公司都有自己的helper。许多Helper提供了很多的强大的功能,封闭交互底层,实体类支持,提供SQL翻译功能。ORM比之这些Helper只是多提供了一层,他尝试封闭的自动化的(或是映射文件)来实现关联。以前,这都是我们手打的。(灵活替换数据库也算ORM优点,ORM优势和缺点。。。(小雨)

  问题就在与有些人发现封闭的自动化关联满足他们需要了,所以ORM对他而言是成功的。而有些人发现封闭的自动化关联不适合他们的项目,所以ORM被诟病。

  写到这里,我想不用多言了。该结束了。
  我的观点是ORM试图取代helper,为此提供了更多的功能。他为了应付更加严格和复杂的企业需求而不断发展,在很多情况下,这些工具开始具有自身的复杂性,使得开发人员必须学习使用它们的详细规则,并修改组成应用程序的类以满足映射系统的需要,使用它们所面临的复杂性反而盖过了所能获得的好处。在我们的大部分项目中Helper依然是我们构建数据持久层的主力,ORM或许在有些项目(模块)中可以独揽一切,但是ORM(就目前而言)无法面对一切考验。




第二部分:

本文来自:http://www.cnblogs.com/tansm/archive/2006/06/07/419927.html

博客园在推广ORM方面的确做了很大的贡献,很多的程序员开始使用ORM,不用写SQL的喜悦让他们激动不已,可是好景不长,他们很快发现众多的烦恼一个接一个的出现了。


很遗憾,我并不打算在这篇文章中解决这些问题,因为的确存在这些问题,而且目前没有完美的解决方法。那么既然这样,我们为什么要使用ORM呢?难道真的是为了不使用SQL吗?

还是要看O - R ,我们为什么要将关系型的数据转化成Object的方式,DataSet的方式难道不好吗?和数据库的表现还是很一致,又简单又方便,为什么先辈们要兴师动众的转化为Object。
我们知道,Object是可以继承的,是可以使用接口的,而Relation没有这个概念。就是因为这一点,我们将实体设计成Object方法,从而获取了大量的优势。
例如:我可以在程序中检测实体是否支持IVersionObject接口,如果支持,我们将自动做版本控制,而如果你给我一个DataSet,那我将无法检测(不要告诉我检测是否存在Version字段)。通过这个特性我们将可以自动化处理很多的事情。
又如,我设计了一个单据实体的基类,包含了SheetCode、SheetDate等等字段,然后我的OrderSheet继承自SheetBase,他们将自动获取到这些标准的字段,而且我的基础类可以自动帮助我处理很多统一的规则,使程序更加稳健和统一。而这个Relation的东西是非常难做到的。

市面上有很多的ORM系统,鱼龙混杂,事实上,相当多的系统根本无法利用Object的继承特性,他们还是一堆的如何做一对多、多对多的概念。根本没有了解到ORM的精髓就做出来。

在这里我需要解释几个误解:
1、ORM使我们摆脱了SQL,但并不代表我们不再使用SQL,事实上,复杂的查询和报表我仍然推荐使用SQL,良好的系统应该可以兼容以前的方式;
2、微软在表模型(Relation)上花费了无数的精力,所以目前Relation的一揽子解决方案是最完整,最好的。但我们看到,微软在.NET 2.0中对Object方式的绑定支持更近了一步,随着LinQ、XAML等很多后续技术的发展,相信领域模型(Object)的完整解决方案将更加完整;

3、ORM更适合复杂的系统(这里使用复杂,而不是大型),而不是小的系统,因为这样的系统要求建造速度快,系统稳定,他们的业务规则异常的复杂,但他们对系统的性能要求并不是很高(相对电信这样的性能要求)。



第三部分:Grove——.NET中的ORM实现

来自:https://msdn.microsoft.com/zh-cn/library/bb608705.aspx#mainSection

发布日期 : 6/30/2005 | 更新日期 : 6/30/2005

作者:林学鹏

ORM的全称是Object Relational Mapping,即对象关系映射。它的实质就是将关系数据(库)中的业务数据用对象的形式表示出来,并通过面向对象(Object-Oriented)的方式将这些对象组织起来,实现系统业务逻辑的过程。在ORM过程中最重要的概念是映射(Mapping),通过这种映射可以使业务对象与数据库分离。从面向对象来说,数据库不应该和业务逻辑绑定到一起,ORM则起到这样的分离作用,使数据库层透明,开发人员真正的面向对象。图 1简单说明了ORM在多层系统架构中的这个作用。

images/grove_001.jpg

图1:ORM在多层系统架构中的作用

目前大多数项目或产品都使用关系型数据库实现业务数据的存储,这样在开发过程中,常常有一些业务逻辑需要直接用写SQL语句实现,但这样开发的结果是:遍地布满SQL语句。这些高藕合的SQL语句给系统的改造和升级带来很多无法预计的障碍。为了提高项目的灵活性,特别是快速开发,ORM是一个不错的选择。举个简单的例子:在使用ORM的系统中,当数据库模型改变时,不再需要理会逻辑代码和SQL语句中涉及到该模型的所有改动,只需要将该模型映射的对象稍作改动,甚至不做改动就可以满足要求。

本页内容

一、ORM的工具实现:Grove 
二、Grove在开发中的实际应用 
三、总结 

一、ORM的工具实现:Grove

优秀的ORM工具不仅可以帮助我们很好的理解对象及对象的关系,而且工具本身会帮助我们维护这些关系。基于这个理念,我设计了基于.NET的ORM工具——Grove ORM Development Toolkit。

Grove ORM Development Toolkit包含Grove和Toolkit两部分内容。Grove为ORM提供对象持久、关系对象查询、简单事务处理、简单异常管理等功能。数据持久包括一些对象的Insert、Delete、Update、Retrieve等功能,关系对象查询则提供一些基于对象的复杂关系查询,包括对应到数据库功能的子查询、关联查询(JOIN)、函数支持(count、avg、max、min)、聚合等。Toolkit是基于VS.NET 2002/2003的VSIP开发的外接程序,职责是帮助开发人员快速映射关系数据库中的业务模型到符合Grove要求的映射实体类,以及映射数据库中复杂关系查询到Grove要求的关系映射实体,暂时只提供C#支持。图 2是Grove内部类实现关系图。

imageFile

图 2: Grove内部类实现关系图

在ORM实现的前期工作中,为了实现屏蔽各种数据库之间的操作差异,我们需要定义数据操作公有接口,封装基本的数据库Insert,Update,Delete,Query等操作。

public interface IDbOperator{int ExecNonQuery(string cmdText);int ExecDataSet(string cmdText,DataSet entity); object ExecScalar(string cmdText);…}

再定义一个数据库操作工厂类,实现各种不同类型数据的适配。

public abstract class DbOperatorFactory:IDbOperator

然后实现各种数据库的操作类,以SQLServer为例。

internal class SqlDbOperator:DbOperatorFactory

完成后,就是ORM主角——实体(Entity)的实现。ORM中实体的定义可以通过实体类自身包含数据模型元数据的方式实现,也可以通过定义XML的元描述实现。下面讲述了通过实体类自身映射的实现。

实体(Entity)是实际业务数据的载体,包含业务数据模型的元描述,可以直接由数据库中的某张表或视图生成,也可以根据需要手工创建。.NET中提供了System.Attribute,该类包含访问和测试自定义属性的简便方法。.NET Framework预定义了一些属性类型并使用它们控制运行时行为。我们可以通过继承System.Attribute基类自定义用于描述实体对象映射时所需要的数据模型元数据,包括表名,字段名,字段长度,字段类型等一些常用的数据。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]public class DataTableAttribute : Attribute

AttributeUsage用来表示该自定义属性可以被绑定在什么样的对象上,这里表示应用在Class或者Struct之上。

抽象一些具有相同特征的属性,使之成为自定义属性的基类。

[AttributeUsage(AttributeTargets.Property)]public class BaseFieldAttribute:Attribute

定义一般字段所需要的自定义属性类。

[AttributeUsage(AttributeTargets.Property)]public class DataFieldAttribute : BaseFieldAttribute

定义关键字字段所需的自定义属性类。

[AttributeUsage(AttributeTargets.Property)]public class KeyFieldAttribute : BaseFieldAttribute

定义外键字段所需要的自定义属性类。

[AttributeUsage(AttributeTargets.Property)]public class ForeignKeyFieldAttribute : BaseFieldAttribute

在以上自定义属性类完成后,我们需要一个用于访问实体在运行期绑定的自定义属性及属性数据的一个Help类。

internal class TypeHelper

实体定义完成后,我们需要根据实体类中绑定的自定义属性构造出运行期需要的SQL语句,为了收集实体类定义中的数据结构描述,我们需要定义一个类来说明实体在运行期所引用到的所有关于数据持久的信息,包括关键字字段,外键字段,一般字段等。

internal class TypeInfo

同时需要一个字段元数据描述类,描述字段在数据库中的名称,大小,是否可为空,列类型等信息。

internal class ColumnInfo

以上条件具备后,我们需要定义一个解析类,负责转换数据的程序类型到数据库字段类型,并且构造出Insert,Update,Delete,Query等操作所需要的SQL语句。

internal class SqlEntityParser

将上面的操作组合起来就是实体类对象操作员。

public class ObjectOperator

实现新增一个记录到数据库中,就是创建了一个新的实体对象,并交由对象操作员进行持久化。

public void Insert(object o){TypeInfo info1=new TypeInfo(o.GetType());//根据实例或者实体描述信息SQLCommand sc=info1.BuildInsertCommand(o);//构造SQL命令对象DbOperator.Parameters=sc.Parameters;//赋值SQL命令所需的参数DbOperator.ExecNonQuery(sc.CommandText);//执行SQL命令}

这里的SQLCommand对象封装了SQL命令处理时所需要的一些值,包含SQL语句,命令参数(Parameter)等。

返回页首 

二、Grove在开发中的实际应用

安装Grove Kit要求Visual Studio 2003 及.NET Framework 1.1支持。从Grove网站下载安装包之后,解压缩GroveKit.zip,执行安装。

在GroveKit安装结束后,打开VS.NET,在VS.NET的启动画面上,您会看到Grove Develop Kit的标志,表示GroveKit已被正确安装。

2.1 生成映射实体类

本文将以C# 项目为例解释Grove在开发中的具体应用。项目名WebApp1,操作系统 Windows 2000,数据库SQL Server 2000,数据库实例名:WebApp1,表结构定义如下:

表名

字段

Customers

CustomerID int(4) PK

CustomerName varchar(50)

CustomerDesc varchar(200)

Status tinyint

Addresses

AddressID int(4) PK

CustomerID int(4) FK

Address varchar(200)

  1. 在VS.NET中,打开“文件->新建->项目”,在Visual C#项目选择ASP.NET WEB应用程序,确定后生成WebApp1项目,在项目中添加对Grove.dll的引用,Grove.dll位于GroveKit的安装路径下,您也可以通过.NET Configuration将Grove添加到程序集缓存中。

  2. 在VS.NET中,打开“工具->Grove Tool Kit”,在GroveToolKit中设置数据库连接属性,并保存。

    images/grove_003.jpg

    图3 设置数据库连接串

  3. 配置当前Web项目的web.config(在</configuration>之前加入以下配置)

    <appSettings><add key="DBConnString" value="Server=localhost;Uid=sa;Pwd=sa;Database=WebApp1" /></appSettings>
  4. 4)在VS.NET解决方案资源管理器中选中Entities,并在GroveToolKit中选择表名,点击GroveToolKit的toolbar中的Preview Entity Class按钮,出现该表的实体映射类预览窗口。

    images/grove_004.jpg

    图4 预览实体映射类

  5. 检查当前预览的实体类,点击生成文件按钮,该实体类将被生成到解决方案资源管理器当前选中的路径下。

  6. 重复4,5步骤就可以生成其他表的映射实体类。

    Customer.csusing System;using Grove.ORM;[DataTable("Customers")]public class Customer{int _CustomerID;string _CustomerName;string _CustomerDesc;int _Status;[KeyField("CustomerID")]public int CustomerID{get{return this._CustomerID;}set{this._CustomerID=value;}}[DataField("CustomerName")]public string CustomerName{get{return this._CustomerName;}set{this._CustomerName=value;}}[DataField("CustomerDesc")]public string CustomerDesc{get{return this._CustomerDesc;}set{this._CustomerDesc=value;}}[DataField("Status")]public int Status{get{return this._ Status;}set{this._ Status=value;}}}
    Address.csusing System;using Grove.ORM;[DataTable("Addresses")]public class Address{int _AddressID;int _CustomerID;string _Address;[KeyField("AddressID")]public int AddressID{get{return this._AddressID;}set{this._AddressID=value;}}[ForeignKeyField("CustomerID")]public int CustomerID{get{return this._CustomerID;}set{this._CustomerID=value;}}[DataField("Address")]public string CustomerAddress{get{return this._Address;}set{this._Address=value;}}}

    代码1.实体映射类

2.2 对象持久化

Grove提供ObjectOperator实现对映射实体对象的数据库持久工作,并通过IObjectQuery接口实现对复杂数据库关系映射实体的查询,主要接口如下:

方法

说明

Insert

新增一个对象

Update

根据条件更新一个对象

Remove

根据条件删除一个对象

RemoveChilds

删除所有关系对象

Retrieve

返回一个对象

RetrieveChilds

返回所有关系对象

GetDataReader

返回IDataReader

GetObjectSet

返回对象集合

GetObjectSource

根据对象定义返回DataSet

GetCount

从数据源返回记录条数

BeginTranscation

在数据库支持事务的基础上,开始事务处理

Commit

完成当前事务

Rollback

回退当前事务

2.3 数据查询

如一般的关系型数据库所具有的查询功能一样,Grove也有着非常丰富的查询功能,如对象查询、函数查询、子查询、排序查询等。这里对对象查询做简单介绍,其它查询读者可以自行参考Grove的开发文档。Grove提供ObjectQuery 帮助ObjectOperator从数据源查询数据, ObjectOperator 需要通过ObjectQuery解析实体对象中的属性(System.Arrtibute)定义,并构造查询语句。ObjectQuery在运行时往往需要定义筛选语句(请参考筛选语句的语法定义)。例如,检索Customer对象,当State 属性等于WA的情况:

ObjectQuery query=new ObjectQuery(typeof(Customer),"this.State='WA'");

当检索需要返回所有对象时,则不需要定义筛选语句

ObjectQuery query=new ObjectQuery(typeof(Customer),"");

2.4 筛选语句的语法定义

在ObjectQuery中使用的筛选允许你在定义的时候,根据使用面向对象语法规则进行定义筛选语句。

操作

描述

!, not

用于比较布尔型,例如:

!Order.CustomerID.Contains(Customer.CustomerID)

<, >, <= , >=

用于值比较,例如:

Order.Quantity >= 12

=, !=, <>, = =

用于值判断,例如:

Customer.Country = 'USA' and Customer.Region != 'WA'

and, &&

用于逻辑判断,例如:

Customer.Country = 'USA' and Customer.Region = 'WA'

or, ||

用于逻辑判断,例如:

Customer.LastName = 'Smith' or Customer.LastName = 'Jones'

返回页首 

三、总结

以上就是ORM的简单实现,复杂的关系对象映射及关系映射实体的查询也是ORM中尤为重要的一块处理,为了屏蔽各数据库之间的SQL差异,很多好的ORM框架都提供一种符合面向对象语言本身语法规则的Query Language支持,例如实现对数据库函数的支持时,会通过定义一些公开的,与编程语言接近的语言来实现,比如说定义Object.Size(),Object.Sum()等类方法式操作语法,在逻辑判断的时候提供一些语言本身的逻辑运算符支持,比如c#中的&&表示and,||表示or等等这些一系列的面向对象编程风格的支持,都很好地为基于关系型数据库支持的系统开发向“面向对象”提供了有力的支持。Grove目前对关系对象查询有很好的支持,感兴趣可以到Grove的网站了解详细信息。


1 0
原创粉丝点击