ASP.NET MVC5+EF6+EasyUI 后台管理系统(58)-DAL层重构

简介:

系列目录

前言:这是对本文系统一次重要的革新,很久就想要重构数据访问层了,数据访问层重复代码太多。主要集中增删该查每个模块都有,所以本次是为封装相同接口方法

   如果你想了解怎么重构普通的接口DAL层请查看第二节点

   如果你只想了解利用T4链接EF生成代码,可以忽略前两节,之后跳后最后T4模版的使用。

  (代码在最后

   补充:

  最后必须让初学者理解一个知识点:分部类 partial 关键字,因为我们的重构是围绕分部类而实现,包括接口

partial 关键字指示可在命名空间中定义该类、结构或接口的其他部分。所有部分都必须使用 partial 关键字。在编译时,各个部分都必须可用来形成最终的类型。各个部分必须具有相同的可访问性,如 publicprivate 等。

如果将任意部分声明为抽象的,则整个类型都被视为抽象的。如果将任意部分声明为密封的,则整个类型都被视为密封的。如果任意部分声明基类型,则整个类型都将继承该类。

指定基类的所有部分必须一致,但忽略基类的部分仍继承该基类型。各个部分可以指定不同的基接口,最终类型将实现所有分部声明所列出的全部接口。在某一分部定义中声明的任何类、结构或接口成员可供所有其他部分使用。最终类型是所有部分在编译时的组合。

下列声明:

partial class Earth : Planet, IRotate { }
partial class Earth : IRevolve { }

等效于下列声明:

class Earth : Planet, IRotate, IRevolve { }

 

知识点:

  1. 改变EF代码生成策略
    1. 改变生成策略为T4
    2. 添加TT模版
  2. 重构DAL层
    1. 创建ICommonRepository<T>接口
    2. 实现ICommonRepository<T>方法
  3. T4模版的使用

1.改变EF代码生成策略旧的ObjectContext改为T4(如果你的项目已经是DBContext API模式请跳过)(操作前备份项目)

在此之前我们也该改变一下代码生成策略,为什么会这个改变。这个项目我最初开始创建的时候用的EF版本为EF4.0当时EF4.0只提供了ObjectContext API接口模式

这个访问方式只能对于DataBase Frist用,不能用于Code Frist.所以一直用到这里,这个并不是很重要,最终都不会影响我们的功能开发

但是DBContext API的亮点,和现在教材都是基于DBContext策略的方式(EF4.1版本之后),我们有必要与时俱进。

操作方式很简单:

第一步:

从旧的ObjectContext改为T4(操作前备份项目)

第二步:

第三步:

->

最后看到DB.emdx下生成了很多模型类。根据表而生成的!这时代码编译将出错,根据出错的类库添加NUGET包。EntityFramework6.1.3版本,添加完之后还会继续报错。

因为ObjectContext有些方法和属性在DBContext已经不能用了

ObjectContext和ObjectSet都提供了AddObject的功能:

           比如 context.AddObject("Students", newStudent):

                  context.Students.AddObject(newStudent):  

           而 DBContext中则只有DBSet有这个功能,并且名称为成了Add

               context.Students.Add(newStudent): 

也包括DeleteObject,ObjectStateManager等。

(忽略所有错误。这些错误将在我们重构DAL层被解决)

2.重构DAL层,下面我们来看一张图

图中绿色部分为本次重构部分,再利用成T4连接EF 生成通用分部类部分。这样我们下次不用手动创建继承类,只需要创建其他操作的分部类,很是简单。来看代码才明白

在第一节下载17讲代码

我们来看现有代码,以SysSample 模块的IDAL和DAL为例子

复制代码
using Apps.Models;
using System.Linq;
namespace Apps.IDAL
{
    public interface ISysSampleRepository
    {
        IQueryable<SysSample> GetList(DBContainer db);
        int Create(SysSample entity);
        int Delete(string id);
        void Delete(DBContainer db, string[] deleteCollection);
        /// <param name="entity">实体</param>
        int Edit(SysSample entity);
        SysSample GetById(string id);
        bool IsExist(string id);
    }
}
复制代码
复制代码
using System;
using System.Linq;
using Apps.IDAL;
using Apps.Models;
using System.Data;

namespace Apps.DAL
{
    public class SysSampleRepository : ISysSampleRepository, IDisposable
    {
        public IQueryable<SysSample> GetList(DBContainer db)
        {
            IQueryable<SysSample> list = db.SysSample.AsQueryable();
            return list;
        }
        public int Create(SysSample entity)
        {
            using (DBContainer db = new DBContainer())
            {
                db.SysSample.AddObject(entity);
                return db.SaveChanges();
            }
        }
        public int Delete(string id)
        {
            using (DBContainer db = new DBContainer())
            {
                SysSample entity = db.SysSample.SingleOrDefault(a => a.Id == id);
                if (entity != null)
                {
                    
                    db.SysSample.DeleteObject(entity);
                }
                return db.SaveChanges();
            }
        }
        public int Delete(DBContainer db, string[] deleteCollection)
        {
            IQueryable<SysSample> collection = from f in db.SysSample
                                               where deleteCollection.Contains(f.Id)
                                               select f;
            foreach (var deleteItem in collection)
            {
                db.SysSample.DeleteObject(deleteItem);
            }
        }
        public int Edit(SysSample entity)
        {
            using (DBContainer db = new DBContainer())
            {
                db.SysSample.Attach(entity);
                db.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
                return db.SaveChanges();
            }
        }
        public SysSample GetById(string id)
        {
            using (DBContainer db = new DBContainer())
            {
                return db.SysSample.SingleOrDefault(a => a.Id == id);
            }
        }
        public bool IsExist(string id)
        {
            using (DBContainer db = new DBContainer())
            {
                SysSample entity = GetById(id);
                if (entity != null)
                    return true;
                return false;
            }
        }
        public void Dispose()
        {

        }
    }
}
复制代码

看到我们其他模块也都必须实现类似代码。其中不同之处只有SysSample模型

好在.net提供索引访问对象的强类型List<T>这里的T代表SysSamle。是可变的

1.接下来我们实现通用接口在IDAL层

 

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Apps.IDAL
{
    public interface ICommonRepository<T> where T :class
    {
        bool Create(T model);
        bool Edit(T model);
        bool Delete(T model);
        /// <summary>
        /// 按主键删除
        /// </summary>
        /// <param name="keyValues"></param>
        int Delete(params object[] keyValues);
        T GetById(params object[] keyValues);
        /// <summary>
        /// 获得所有数据
        /// </summary>
        /// <returns></returns>
        IQueryable<T> GetList();
        /// <summary>
        /// 根据表达式获取数据
        /// </summary>
        /// <param name="whereLambda"></param>
        /// <returns></returns>
        IQueryable<T> GetList(Func<T, bool> whereLambda);bool IsExist(string id);
        int SaveChanges();
    }
}
复制代码

 代码解析:接口实现了增删改查通用接口,并声明 where T :class 【T必须是一个类(class)类型】

2.接下来我们实现通用方法DAL层 按照重构图所示,应该继承ICommonRepository接口,并实现接口方法

复制代码
using Apps.IDAL;
using Apps.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Apps.DAL
{
    public abstract class CommonRepository<T> : ICommonRepository<T> where T:class
    {
        DBContainer db;
        public CommonRepository(DBContainer context)
        {
            this.db = context;
        }

        public DBContainer Context
        {
            get { return db; }
        }

        public virtual bool Create(T model)
        {
            db.Set<T>().Add(model);
            return db.SaveChanges()>0;
        }

        public virtual bool Edit(T model)
        {
            if (db.Entry<T>(model).State == EntityState.Modified)
            {
                return db.SaveChanges() > 0;
            }
            else if (db.Entry<T>(model).State == EntityState.Detached)
            {
                try
                {
                    db.Set<T>().Attach(model);
                    db.Entry<T>(model).State = EntityState.Modified;
                }
                catch (InvalidOperationException)
                {
                    //T old = Find(model._ID);
                    //db.Entry<old>.CurrentValues.SetValues(model);
                }
                return db.SaveChanges()>0;
            }
            return false;
        }

        public virtual bool Delete(T model)
        {
            db.Set<T>().Remove(model);
            return db.SaveChanges()>0;
        }

        public virtual int Delete(params object[] keyValues)
        {
            T model = GetById(keyValues);
            if(model!=null)
            {
                db.Set<T>().Remove(model);
                return db.SaveChanges();
            }
            return -1;
        }
        public virtual T GetById(params object[] keyValues)
        {
            return db.Set<T>().Find(keyValues);
        }

        public virtual IQueryable<T> GetList()
        {
            return db.Set<T>();
        }

        public virtual IQueryable<T> GetList(Func<T, bool> whereLambda)
        {
            return db.Set<T>().Where(whereLambda).AsQueryable();
        }
        public virtual bool IsExist(string id)
        {
            return GetById(id)!=null;
        }

        public int SaveChanges()
        {
           return db.SaveChanges();
        }
    }
}
复制代码

 OK.全是DBContext API 操作EF方法。增删改查

3.T4生成分部类

接下来我们来看这么用这个接口

我们IDAL所有表(即模块)都要实现ICommonRepository接口好调用其中的增删改查做扩展

删掉ISysSampleRepository中的原来代码变为:

复制代码
using Apps.Models;
using System.Linq;
namespace Apps.IDAL
{
    public interface ISysSampleRepository : ICommonRepository<SysSample>
    {
      
    }
}
复制代码

观察到这里也是重复代码,因为同理我们所有表都要实现这样的接口,这样我们可以利用T4来生成这种的重复代码

我以前写过一篇文章是关于T4链接数据库的。构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(29)-T4模版

这里我们是直接链接edmx的。同理

1.新建一个文件夹。如下图所示并创建一个TT模版

创建后会产生2个文件。删掉Context.tt,因为在Apps.Models已经有了

 配置第五行的inputFile为上面所描述,可能因为环境不同你们EF路径有所不同。保存后TT模版会自动生成

tt模版如果没有高亮显示的。要安装一些工具。因为我是一边改一边发文章的。我这里也是没有的,下载T4Editor 安装高亮,什么版本就下什么就可以了(或者通过VS工具------扩展与更新 搜索)

http://t4-editor.tangible-engineering.com/Download_T4Editor_Plus_ModelingTools.html

tangible T4 Editor 2.3.0 plus modeling tools for Visual Studio 2015Download from Visual Studio Gallery

tangible T4 Editor 2.3.0 plus modeling tools for Visual Studio 2013Download from Visual Studio Gallery

按照ISysSampleRepository接口为例子。修改TT模版后代码

  ICommonRepository

核心代码解析:

复制代码
foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection))
{
    fileManager.StartNewFile("I"+entity.Name + "Repository.cs");
#>
using Apps.Models;
namespace Apps.IDAL
{
    public partial interface I<#=entity.Name #>Repository:ICommonRepository<<#=entity.Name #>>
    {
    
    }
<#
    EndNamespace(code);
}

fileManager.Process();

#>
复制代码

循环生成。达到预期效果

 TT模版里面太多代码很难看懂,需要看官方帮助文档才行。但是我们可以提取公共部分。以后写TT就引入。看图

在WriteHeder方法后都是通用的访问代码。我们提取之后的代码。因为安装了T4高亮。我只能调浅色,深色效果太差

在Apps.Models创建 Common.ttinclude来做公共部分(你可以创建在其他路径,到时候是引入路径为准)

最后修改:ICommonRepository.tt第二行代码:

<#@ include file="../../Apps.Models/Common.ttinclude"#><#@ 

OK。看起来间接很多了,以后创建其他tt文件就可以直接引用公共部分,如果不提取tt模版也是没有问题的。

同理我们创建DAL层的公共部分,生成后的代码如下,同样是一个分部类CommonRepository

  CommonRepository.tt
复制代码
//------------------------------------------------------------------------------
// <auto-generated>
//     此代码已从模板生成。
//
//     手动更改此文件可能导致应用程序出现意外的行为。
//     如果重新生成代码,将覆盖对此文件的手动更改。
// </auto-generated>
//------------------------------------------------------------------------------

using Apps.Models;
using Apps.DAL;
namespace Apps.IDAL
{
    public partial class SysSampleRepository:CommonRepository<SysSample>
    {
        public SysSampleRepository(DBContainer db):base(db)
        {
        
        }
    }
}
复制代码

接下来原来很长的ISysSampleRepository接口最后变成了一个分部接口

复制代码
using Apps.Models;
using System.Linq;
namespace Apps.IDAL
{
    public partial interface ISysSampleRepository
    {
       //处理通用部分外的业务
    }
}
复制代码

SysSampleRepository变成了一个分部类

复制代码
using System;
using System.Linq;
using Apps.IDAL;
using Apps.Models;
using System.Data;

namespace Apps.DAL
{
    public class SysSampleRepository
    {
    //处理通用部分外的业务
} }
复制代码
 

可以处理通用部分外的业务

这样我们关注点真的很专注了。Ye...

关于业务层,肯定还是报错的状态,这时候我们就来修改一下

例如:

变为

最后业务层代码:

  View Code

--------------------------------------------------------------------------------写在最后--------------------------------------------------------------------------------

可以对比以前DAL层的代码,明显的减少很多(虽然业务层没有减少)。也许在以后业务层也有必要的重构!

最后我完全修改了我项目的DAL层。用数据直接说话

 

整整少了两万行。却完成了相同的功能。(代码类型.cs,与事实可能有点差别,但是可以效果明显)

代码参考下载。重构后的架构(VS2013)执行根目录下的script.sql脚本。并修改web.config数据库链接即可查看

如查看重构前代码可以到第一节下载17节代码

https://yunpan.cn/cYUdjssbmiLrL  提取码 e622


本文转自ymnets博客园博客,原文链接:http://www.cnblogs.com/ymnets/p/5306935.html,如需转载请自行联系原作者

相关文章
|
5月前
基于EasyUI的后台管理系统页面原型_示例图_下载地址
基于EasyUI的后台管理系统页面原型_示例图_下载地址
31 0
|
数据可视化 安全 Java
【项目源码】基于spring boot+mybatis+easyui开发的质量溯源系统
粮油溯源系统是从种植到加工、包装、库存、物流、销售、售出、异常反馈的全流程可视化质量溯源系统。技术架构:spring boot+mybatis+easyui+mysql
144 0
【项目源码】基于spring boot+mybatis+easyui开发的质量溯源系统
|
Java 关系型数据库 MySQL
Eclipse+Java+SSM+Easyui实现网上考试系统
Eclipse+Java+SSM+Easyui实现网上考试系统
150 0
Eclipse+Java+SSM+Easyui实现网上考试系统
|
安全 数据安全/隐私保护
EasyUI+JavaWeb奖助学金管理系统[20]-项目总结与展望
本文目录 1. 总结 1.1 管理员新增奖助学金项目 1.2 学生发起申请 1.3 班主任审批 1.4 学院管理员审批 1.5 学校管理员审批 1.6 学生查看申请结果 2. 展望
172 0
EasyUI+JavaWeb奖助学金管理系统[20]-项目总结与展望
|
项目管理 数据安全/隐私保护
EasyUI+JavaWeb奖助学金管理系统[16]-权限管理功能的开发
本文目录 1. 本章任务 2. 页面布局 3. 加载角色对应的菜单 4. 提交角色菜单信息 5. 小结
156 0
EasyUI+JavaWeb奖助学金管理系统[16]-权限管理功能的开发
|
前端开发
EasyUI+JavaWeb奖助学金管理系统[14]-机构新增、编辑、删除的实现
本文目录 1. 本章任务 2. 新增功能的实现 2.1 添加新增弹窗 2.2 页面初始化时加载上级机构列表 2.3 后端提供获取机构列表方法 2.4 点击保存后将内容提交 2.5 后端处理新增保存请求 2.6 测试 3. 编辑功能的实现 4. 删除功能的实现 5. 总结
162 0
EasyUI+JavaWeb奖助学金管理系统[14]-机构新增、编辑、删除的实现
|
前端开发
EasyUI+JavaWeb奖助学金管理系统[19]-奖助学金审批功能开发
本文目录 1. 本章任务 2. 查看当前待审批的申请 3. 审批功能的开发 4. 总结
202 0
|
存储 数据库
EasyUI+JavaWeb奖助学金管理系统[18]-奖助学金申请功能开发
本文目录 1. 本章任务 2. 数据库表结构分析 3. 学生查看申请记录功能开发 4. 学生发起申请功能开发 5. 总结
280 0
|
项目管理 数据库 数据安全/隐私保护
EasyUI+JavaWeb奖助学金管理系统[17]-问题反馈功能开发
本文目录 1. 本章任务 2. 添加菜单 3. 学生问题反馈开发 4. 管理员问题答复功能开发 5. 总结
171 0
|
存储 项目管理 数据库
EasyUI+JavaWeb奖助学金管理系统[15]-人员管理功能实现
本文目录 1. 本章任务 2. 人员分页浏览的实现 3. 人员新增功能的实现 3. 人员编辑功能的实现 4. 人员删除功能的实现 5. 本章完整源代码 5.1 userManager.html 5.2 CoreServlet.java 5.3 UserDao.java 6. 总结
181 0