名字起得有点夸张了,其实就是实现 基于 data access application block的dal基类和约束 首先repository部分没什么好描述的,如果有不了解的可以直接百度或者谷歌相关内容,直接上具体代码 注意此部分没有写批量查询的方法(比如findall,这跟后面的基类设定
名字起得有点夸张了,其实就是实现基于data access application block的dal基类和约束
首先repository部分没什么好描述的,如果有不了解的可以直接百度或者谷歌相关内容,直接上具体代码
注意此部分没有写批量查询的方法(比如findall,这跟后面的基类设定有关)
/// /// dataaccess repository /// /// /// public interface irepository { /// /// 根据主键获取对应的实体对象 /// /// /// t1 getentitybykey(t2 key); /// /// 单个新增 /// /// /// bool insert(t1 entity); /// /// 单个编辑 /// /// /// bool update(t1 entity); /// /// 单个删除 /// /// /// bool delete(t2 key); }
然后是dal抽象基类,该基类设计上实现读写分离,而且每个子类只应有一个数据库连接,这样做的隐藏目的是每个dal类都只应该执行自己最基本的功能:只关心数据库交互,不关心业务逻辑
/// /// dal基类,基于entlib,读写分离 /// public abstract class dataaccessbase { private database _readdb; private database _writedb; /// /// 要使用的读数据库配置节,如果配置为null或者空则会调用默认配置节 /// protected abstract string readdbname { get; } /// /// 要使用的写数据库配置节,如果配置为null或者空则会调用默认配置节 /// protected abstract string writedbname { get; } /// /// 读库 /// protected database readdb { get { if (this._readdb == null) { this._readdb = this.getdatabase(this._writedb, this.readdbname); } return this._readdb; } } private database getdatabase(database db, string dbname) { if (this.readdbname == this.writedbname && db != null) { return db; } else { return this.createdatabase(dbname); } } /// /// 写库 /// protected database writedb { get { if (this._writedb == null) { this._writedb = this.getdatabase(this._readdb, this.writedbname); } return this._writedb; } } private database createdatabase(string dbname) { databaseproviderfactory factory = new databaseproviderfactory(); if (string.isnullorwhitespace(dbname)) { return factory.createdefault(); } else { return factory.create(dbname); } } }
最后就是irepository接口与dataaccessbase的组合实现singledataaccessbase,为什么不在dataaccessbase时就实现irepository呢?因为设计上dataaccessbase是可以同时运用于多表操作及单表操作的,多表操作时,irepository不存在任何意义,只有单表操作时,irepository才有意义,而singledataaccessbase就是单表dal基类 using system.collections.generic; using system.linq; using microsoft.practices.enterpriselibrary.data; using system.data.common; /// /// 单表dataaccess基类,所有单表dataaccess应当继承此类,建议非共用部分同样实现接口 /// 多表但单数据库操作的dataaccess不能继承此类,而应继承dataaccessbase /// /// /// public abstract class singledataaccessbase : dataaccessbase, irepository where t1 : new() { #region sqlstring /// /// getentitybykey方法对应的sql语句 /// protected abstract string selectsql { get; } /// /// insert方法对应的sql语句 /// protected abstract string insertsql { get; } /// /// update方法对应的sql语句 /// protected abstract string updatesql { get; } /// /// delete方法对应的sql语句 /// protected abstract string deletesql { get; } #endregion #region irepository 成员 /// /// 根据主键获取对应的实体对象 /// /// /// public virtual t1 getentitybykey(t2 key) { return this.readdb.executebysqlstring(this.selectsql, null, (irowmapper)null, this.getkeyparameters(key).toarray()).firstordefault(); } /// /// 单个新增,如果是自增主键,则需要override /// /// /// public virtual bool insert(t1 entity) { return this.writedb.executenonquerybysqlstring(this.insertsql, (cmd) => { this.setparametersbyentity(entity, cmd); }) > 0; } /// /// 单个编辑 /// /// /// public virtual bool update(t1 entity) { return this.writedb.executenonquerybysqlstring(this.updatesql, (cmd) => { this.setparametersbyentity(entity, cmd); }) > 0; } /// /// 单个删除 /// /// /// public virtual bool delete(t2 key) { return this.writedb.executenonquerybysqlstring(this.deletesql, (cmd) => { this.setparametersbykey(key, cmd); }) > 0; } #endregion #region methods /// /// 通过entity填充dbparameter /// /// /// protected abstract void setparametersbyentity(t1 entity, dbcommand cmd); /// /// 通过key填充dbparameter /// /// /// protected virtual void setparametersbykey(t2 key, dbcommand cmd) { var paramters = this.getkeyparameters(key); cmd.parameters.addrange(paramters.toarray()); } /// /// 通过协变的方式根据key获取对应的dbparameter /// /// /// protected abstract ienumerable getkeyparameters(t2 key); #endregion }
这里singledataaccessbase其实并不能算实现了irepository,只是进行了相关的约束规范而已,实际子类需要提供相应的sqlstring以及parameter实现(注意此处用到了前面博客中写的微软企业库扩展,具体见[entlib]微软企业库6 data access application block 扩展),因为data access application block其实并不是一个orm,如果采用这个类库,其实已经有比较大的概率可以确定系统对性能的要求较高,当然你也可以通过反射之类的实现真正的repository(前提是你的poco与关系型数据库中字段能对应上)
singledataaccessbase子类建议划分区域块,对应的代码写入对应区域,如
#region connectionsetting protected override string readdbname { get { throw new notimplementedexception(); } } protected override string writedbname { get { throw new notimplementedexception(); } } #endregion #region sqlstring protected override string selectsql { get { throw new notimplementedexception(); } } protected override string insertsql { get { throw new notimplementedexception(); } } protected override string updatesql { get { throw new notimplementedexception(); } } protected override string deletesql { get { throw new notimplementedexception(); } } #endregion #region read #endregion #region write #endregion #region dbparameter protected override void setparametersbyentity(t1 entity, dbcommand cmd) { throw new notimplementedexception(); } protected override ienumerable getkeyparameters(t2 key) { throw new notimplementedexception(); } #endregion
可能很多人觉得区分多表操作的dal和单表操作的dal没有必要或者没有意义,的确,在功能上,写在一个里面和写在多个里面没有区别,系统较小时还没有什么问题,如果系统较大,经由的开发人员较多时,很可能会出现某个开发人员想要用到某个表的某些字段,但因为系统较大又没有相关约束,导致该开发人员不知道去哪里找是否该方法已经存在,为了简易起见,最常见的做法是直接在自己需要的地方新写这部分代码,而最终的后果就是,代码分布越来越混乱,当表结构发生变化时,此部分尤其变成了灾难,因为如果不通过查表名,你根本无法预见到底哪些地方用到了这张表!而区分单表及多表操作,就是要解决这样的问题,当表结构发生变化时,也只需要找该表对应的单表dal以及以数据库对应的多表dal两个地方
最后吐槽下,企业库5真心伤不起,为了用dataaccess模块,连连千千添加了5个相关dll引用,真心怪不得人家不愿意用,还好6没了这个问题……