首先、园子里面以前的不少同仁已经讨论过了ORM相关的框架及其优势和缺点。虽然我本篇讨论的有点晚,可是其毕竟优势大于缺点,本文只是简单的介绍我讨html
论ORM的目的,及为何要讨论这个已经被你们讨论的成熟的不能再成熟的东西。sql
咱们先来看看ORM的优缺点:数据库
本篇将详细分析为何咱们要使用ORM,及ORM前篇的分析建模。框架
本篇主要是分析ORM框架的优缺点及项目中的取舍,找到突破点,而且经过图形化的方式分析ORM应该具有的基本功能及如何构建ORM中的核心模块。这里面简单函数
列举出ORM中的核心模块:性能
下面将分别讲解和分析实现方案。测试
一、摘要。优化
二、本章简介。ui
三、本章内容。this
四、ORM的应用性分析。
五、ORM设计分析。
六、本章总结。
七、系列进度。
八、下篇预告。
首先、在软件开发中咱们都知道OO面向对象的思想对咱们现有的软件开发意义,咱们能够把软件开发的过程理解为将现实社会的抽象过程。面向对象的思想把现
实世界抽象为万物皆为对象,经过对象之间的交互完成全部的活动。OO出现以前的软件开发都是面向过程的开发思想。面向过程关系的是过程而不是对象。在某个动做
过程当中的步骤,经过一系列的函数来解决问题。
面向对象则把一切事物看做对象,而过程就是对象之间的交互或是对象内部的活动。
咱们知道目前流行的数据库都是关系型数据库,二维的数据库结构。咱们如何将某个对象与这个实体对应起来呢?这就成了咱们更关心的问题,这时候ORM思想
的出现解决了这样的问题。
上图反映了实体对象与数据库表的关系,一个实体对象对应数据库表中的一个行记录。而经过DDL操做中的查询方法,来将数据库表中的行纪录映射到多个实体对
象中。而经过ORM提供的DDL操做方法,将实体对象的数据持久化到对应的数据库表中。
另一个须要注意的问题就是当实体中的属性添加或减小时或是数据库表中的结构发生变化时,如何作到实体中的属性与数据库表中的列一一对应这是个每一个ORM
头疼的问题,由于ORM没法实现自动的同步这样的变化。固然目前的大名鼎鼎的Nhibernate在这方面也是处理的比较灵活,这是必须确定的。固然在这个系列中咱们也
会详细的讲解实现的思路与方案,如何处理实体与数据库表结构发生变化时的同步问题,固然这和采用的ORM的实现方式有关。
ORM思想给我提供了以下的方便:
固然ORM框架也不是万能的,有优势的必然存在这必定的缺点,咱们来看看ORM的不足:
经过上面的分析咱们简单的了解了ORM的优缺点,那么如何在项目中应用它呢,咱们在使用某个技术时确定是扬长避短,因此ORM也是同样的道理,若是咱们在项目中有大量的DDL操做语句,而且对业务逻辑之间的多实体间的关联关系不是特别的紧密时,那么用ORM技术就会比较好。
若是在项目中多表的关联查询比较多,而且表之间的逻辑关系比较复杂时就不推荐用ORM来处理。不但会提升项目的复杂度,维护起来代价也比较大。例如像统
计分析系统。用ORM来实现就比较麻烦。
首先咱们来看看数据库访问的通用组件模型:
上图大概画出了比较经常使用的几类数据库,经过ORM中的数据库访问组件来实现数据库的访问。固然咱们这里经过定义数据库访问统一接口的形式,让全部的数据
库访问类都默认继承实现这个接口。
实例代码以下:
public interface IDBAccessor { /// <summary> /// 执行Update,Delete,Insert语句方法 /// </summary> /// <returns>返回影响的行数</returns> int Excute(); /// <summary> /// 执行查询方法 /// </summary> void Query(); }
接口中只是定义了简单的DDL语言中的四个基本的操做。
下面看每一个不一样数据库的实现方法。
SQLServer数据库
public class SQLServer : IDBAccessor { #region IDBAccessor 成员 private string commandStr = string.Empty; private static string connectionString = ""; private System.Data.IDbConnection sqlConnection = new System.Data.SqlClient.SqlConnection(connectionString); public int Excute() { if (sqlConnection.State != System.Data.ConnectionState.Open) sqlConnection.Open(); try { using (System.Data.IDbCommand command = sqlConnection.CreateCommand()) { command.CommandText = commandStr; return command.ExecuteNonQuery(); } } catch(System.Exception) { return -1; } finally { } } public void Query() { } #endregion }
Oracle数据库
public class Oracle : IDBAccessor { #region IDBAccessor 成员 private string commandStr = string.Empty; private static string connectionString = ""; private System.Data.IDbConnection oraConnection = new System.Data.OracleClient.OracleConnection(connectionString); public int Excute() { if (oraConnection.State != System.Data.ConnectionState.Open) oraConnection.Open(); try { using (System.Data.IDbCommand command = oraConnection.CreateCommand()) { command.CommandText = commandStr; return command.ExecuteNonQuery(); } } catch (System.Exception) { return -1; } finally { } } public void Query() { throw new NotImplementedException(); } #endregion }
其余的几个类型的数据库咱们就不一一举例说明了,固然我这里面的接口中并无考虑把数据库链接也定义成接口,让全部的都从这个接口进行继承,由于这个不是
本章讨论的重点,本章只是简单的分析与设计如何实现通用把数据层访问。
下面咱们来讲说对象关系映射的实现。
咱们比较常见的方式目前就这样的2种方式,第一种方式想必你们都比较了解的,不管是JAVA中的Hibernate仍是.NET中的Nhibernate都是这样的方式,以XML文
件的方式把数据库中的表列属性与实体的属性一一对应。第二种方式则是在类文件中硬编码书写数据库列与实体之间的映射关系。
下面咱们来分析下这二种方式的利弊:
以上大概描述了各自的有点,下面再阐述下各自的缺点。
固然以上的2种形式各有优缺点,咱们已经讲述了XML配置文件中现有的开源框架中采用这种形式的框架有Nhibernate。而采用类文件映射的框架其实有不少,但
是他们的思想相对来讲都是同样的。不论是XML文件形式,仍是类文件形式,他们的主要观点都是实现如何把实体的属性与数据库表字段的对应,这个才是核心的内容。
下面咱们给出一种简单的思路去完成这样的映射,固然咱们这里是以类文件形式给出示例。
其实博客园的不少人都写过类文件映射的实例。我这里固然也只是抛砖引玉,不足之处在所不免,还请你们多多提出意见。
我给出的方式是经过特性(Attribute)+反射(Rflection)的思想来实现ORM映射。
具体相应代码以下:
/// <summary> /// Model中的字段属性特性 /// </summary> [AttributeUsage(AttributeTargets.All, AllowMultiple = false)] public class PropertyAttribute : Attribute { private string dbColumnName; private bool isPrimary; private DbType dbType; private object defaultValue; private bool isIdentify; private int length; public string DbColumnName { get { return this.dbColumnName; } set { this.dbColumnName = value; } } public bool IsPrimary { get { return this.isPrimary; } set { this.isPrimary = value; } } public bool IsIdentify { get { return this.isIdentify; } set { this.isIdentify = value; } } public DbType DbType { get { return this.dbType; } set { this.dbType = value; } } public object DefaultValue { get { return this.defaultValue; } set { this.defaultValue = value; } } public int DbLength { get { return this.length; } set { this.length = value; } } public PropertyAttribute(string dbName, bool isPrimery, DbType type,object dValue) { this.dbColumnName = dbName; this.isPrimary = isPrimery; this.dbType = type; this.defaultValue = this.GetDefaultValue(); } private object GetDefaultValue() { return new object(); } public PropertyAttribute(string dbName) { this.dbColumnName = dbName; this.isPrimary = false; this.dbType = DbType.String; this.defaultValue = this.GetDefaultValue(); } public PropertyAttribute(string dbName,bool isPrimery) { this.dbColumnName = dbName; this.isPrimary = isPrimery; this.dbType = DbType.String; this.defaultValue = this.GetDefaultValue(); } public PropertyAttribute(string dbName, bool isPrimery, DbType type) { this.dbColumnName = dbName; this.isPrimary = isPrimery; this.dbType = type; this.defaultValue = null; } }
上面给出的是字段属性上定义的特性,咱们来看看表的特性:
/// <summary> /// 基于表的自定义特性类 /// </summary> [AttributeUsage(AttributeTargets.All, AllowMultiple = false)] public class TableAttribute : Attribute { private string dbTableName; public TableAttribute(string dbName) { this.dbTableName = dbName; } public string TableName { get { return this.dbTableName; } set { this.dbTableName = value; } } }
在实体层的具体使用以下:
/// <summary> /// 管理员帐户ID /// </summary> [PropertyAttribute("",false,System.Data.DbType.Int32,0)] public int AdminId { set { _adminid = value; } get { return _adminid; } }
基于表上的特性以下使用:
[TableAttribute("es_memberaccount")] public class Account { public Account() { } }
下面看看如何在生成SQL语句层中的处理方法:
/// <summary> /// 返回Model对应的数据库表名 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="model"></param> /// <returns></returns> public string DbTableName<T>(T model) { string dbName = string.Empty; DPM.Common.TableAttribute attr = null; object[] attributes = model.GetType().GetCustomAttributes(typeof(DPM.Common.TableAttribute), true); if (attributes.Length > 0) { attr = (DPM.Common.TableAttribute)attributes[0]; } if (attr != null) dbName = attr.TableName; return dbName; } /// <summary> /// 返回数据库表中的全部数据列 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="model"></param> /// <returns></returns> public string InitDbColumns<T>(T model) { StringBuilder commandBuilder = new StringBuilder(); DPM.Common.PropertyAttribute attr = null; foreach (PropertyInfo property in model.GetType().GetProperties()) { object[] attributes = property.GetCustomAttributes(typeof(DPM.Common.PropertyAttribute), true); if (attributes.Length > 0) { attr = (DPM.Common.PropertyAttribute)attributes[0]; } commandBuilder.Append(attr.DbColumnName+”,”); } return commandBuilder.ToString().Substring(0,commandBuilder.ToString().Length-1); }
本章简单讲述了ORM实现的基本思路分析及ORM框架使用的优缺点及在项目中如何合理的分析与应用。下面咱们来简单总结下本章讲解的内容。
本章主要讲述了ORM的优势:减小工做流,复用性高,开发速度快,更关注业务方面的开发,将DDL操做中除了联合查询实现起来比较复杂外,其余的基本上都
能正常的处理。缺点:一对多或者多对多的关联关系没法很好的知足需求外,还有就是性能上会有必定的影响。在项目中应根据项目的业务需求来决定是否在项目中使
用ORM框架来解决问题。
二、Step by Step-构建本身的ORM系列-数据访问层
三、Step by Step-构建本身的ORM系列-配置管理层
四、Step by Step-构建本身的ORM系列-对象映射层[上]
五、Step by Step-构建本身的ORM系列-对象映射层[中]
六、Step by Step-构建本身的ORM系列-对象映射层[下]
七、Step by Step-构建本身的ORM系列-测试ORM框架
八、Step by Step-构建本身的ORM系列-瓶颈、优化
九、Step by Step-构建本身的ORM系列-实例
下篇咱们将讲解如何实现通用的数据访问层,将会详细的介绍如何设计出通用的数据访问层,而且采用设计模中的2个原则:低耦合、高内聚等一些设计规范和原
则。欢迎你们拍砖和提出好的意见和建议。