本系列文章将介绍如何在.Net框架下,从零开始搭建一个完成CRUD的Framework,该Framework将具备以下功能,基本实体结构(基于DDD)、基本仓储结构、模块加载系统、工作单元、事件总线(EventBus,具有事件溯源的功能)、以及依赖注入管理系统.

1、简介

本文将通过源码和代码注释和文字说明来解释基本实体结构的构建和基本仓储的构建

2、实战

(1)、基本实体的构建

在OOP的概念之下,对象大致可以分为两类,持久化对象和非持久化对象.本文主要讨论的是持久化对象,即需要写入到数据库或者其他数据容器中的对象,也就是实体(当然这里不是所谓的实体,而是通过OOP技术构建出来的一个实体结构,这个结构需要满足日常开发中绝大多数的业务需求).接下去,就是使用OOP技术来构建这个实体结构.

首先这个实体既然需要写入数据库,那么它必定有一个主键Id.同时这个主键Id可以是任意数据类型,当然用的最多的就是GUID和INT作为主键.前面全局唯一,后者查询效率快.

所以,就有了如下结构:

    public interface IEntity<TPrimaryKey>
    {
        /// <summary>
        /// 实体的主键Id
        /// </summary>
        TPrimaryKey Id { get; set; }
    }

其次,以不同数据类型(GUID、int、string)为主键的实体类型,存在一些共有方法,比如需要编写更加语义化的ToString方法,所以当不同类型需要共同的实现的时候,这个时候就需要一层抽象,来处理这层关系,所以就有了如下结构:

  [Serializable]
 public abstract class Entity<TPrimaryKey> : IEntity<TPrimaryKey> { public TPrimaryKey Id { get; set; } /// <summary> /// 返回当前实体的类型名称+Id的形式 /// </summary> /// <returns></returns> public override string ToString() { return $"{GetType().Name} {Id}"; } }

当然这个结构中可以有任何的共有方法,只要它们能成功的抽象出来,就能写入到里面.

接着,基本实体就出现了,这里我分为两类,一类以int为主键,一类已Guid主键,为别写道两个类中,如下代码:

    /// <summary>
    /// 以int为主键的实体类型
    /// </summary>
    [Serializable]
    public abstract class Entity: Entity<int>
    {

    }

    /// <summary>
    /// 以Guid为为主键的实体类型
    /// </summary>
    [Serializable]
    public abstract class GEntity : Entity<Guid>
    {

    }

打上Serializable特性,方便序列化.这里不同的子类使用abstract来实现,也是为了提供各自实体的共有抽象属性(或者方法).到这一步,最最基本的实体抽象构建完毕,但是还没有结束,因为这个结构可以继续优化.使它可以为我们的业务更好的服务.所以需要持久化的实体必定存在一个创建的过程,可能该实体在某些业务下不需要修改、删除或者查询功能,但是它有极大的概率存在一个创建的过程,所以这里需要构建一个实体创建的抽象类,代码如下:

    public interface ICreationAudited
    {
        /// <summary>
        /// 创建该实体的用户Id
        /// </summary>
        int? CreatorUserId { get; set; }

        /// <summary>
        /// 创建当前实体时的时间
        /// </summary>
        DateTime CreationTime { get; set; }
    }

    [Serializable]
    public abstract class CreationAuditedEntity<TPrimaryKey> : Entity<TPrimaryKey>, ICreationAudited
    {
        public int? CreatorUserId { get; set; }

        public DateTime CreationTime { get; set; }

        /// <summary>
        /// 构造 当前实体注入内存时,给定创建时间,存在误差,因为从业务点击页面创建到实际生成该实体阶段存在时间差,但是这个时间差可以忽略不计
        /// </summary>
        protected CreationAuditedEntity()
        {
            CreationTime = DateTime.Now;
        }
    }

    /// <summary>
    /// 实体创建      主键为int
    /// </summary>
    [Serializable]         public abstract class CreationAuditedEntity : CreationAuditedEntity<int>
    {

    }

这里考虑文章大小,Guid的实体创建类型就不实现了,接下去只实现int.

最后实体创建的结构,构建完毕之后,在编写一个需要增删查改所有功能都具备的实体结构,整个实体结构大致就构建完毕了,代码如下:

    public interface IDeletionAudited
    {
        /// <summary>
        /// 删除实体的用户Id
        /// </summary>
        int? DeleterUserId { get; set; }

        /// <summary>
        /// 删除实体的时间
        /// </summary>
        DateTime? DeletionTime { get; set; }
    }

    public interface IModificationAudited
    {
        /// <summary>
        /// 最后一次修改实体的用户Id
        /// </summary>
        int? LastModifierUserId { get; set; }

        /// <summary>
        /// 最后一次修改实体的时间
        /// </summary>
        DateTime? LastModificationTime { get; set; }
    }

    public interface IFullAudited : IDeletionAudited, IModificationAudited, ICreationAudited
    {

    }

    [Serializable]
    public abstract class FullAuditedEntity<TPrimaryKey>:CreationAuditedEntity<TPrimaryKey>,IFullAudited
    {
        public int? DeleterUserId { get; set; }

        public DateTime? DeletionTime { get; set; }

        public int? LastModifierUserId { get; set; }

        public DateTime? LastModificationTime { get; set; }
    }

    /// <summary>
    /// 具有增删查该功能的实体结构 主键为int
    /// </summary>
    public abstract class FullAuditedEntity : FullAuditedEntity<int>
    {

    }

ok,到这里基本的实体结构构建完毕,当然这里你可以随意的扩展,比如构建各种各样的默认的实体类,如主键为string的只具有修改和删除的实体类.可以根据业务的实体特性来动态的扩展.也可以向所有的抽象实体类中添加任意的抽象属性或者方法.比如给Entity添加获取HashCode的共有方法.

(2)、基本仓储结构的构建

关于仓储就不多介绍了,可以自行上网查阅相关的文章,基本仓储结构是依赖于实体结构的。本文将基本Dapper构建一套基本仓储结构.

首先必须有一个仓储接口标识,这个标识本身不具有方法,单单只是一个标识,方便后期实现工作单元和模块加载系统时,辨别出程序集中的仓储类型.如下:

    /// <summary>
    /// 仓储接口
    /// </summary>
    public interface IRepository
    {

    }

接着,基于这个接口来构建Dapper通用仓储具有的基本的功能,即增删查改、分页、列表等功能.代码如下:

    /// <summary>
    /// Dapper通用仓储接口
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TPrimaryKey"></typeparam>
    public interface IDapperRepository<TEntity, TPrimaryKey> : IRepository where TEntity : class, IEntity<TPrimaryKey>
    {
        /// <summary>
        /// 添加一条实体信息
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        Task InsertAsync(TEntity entity);

        /// <summary>
        /// 删除一条实体信息
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        Task DeleteAsync(TEntity entity);

        /// <summary>
        /// 修改一条实体信息
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        Task UpdateAsync(TEntity entity);

        /// <summary>
        /// 根据主键Id异步获取一条数据信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Task<TEntity> GetAsync(TPrimaryKey id);

    }
[Serializable]

.Net 从零开始构建一个框架之基本实体结构与基本仓储构建的更多相关文章

  1. 从零开始构建一个的asp.net Core 项目

    最近突发奇想,想从零开始构建一个Core的MVC项目,于是开始了构建过程. 首先我们添加一个空的CORE下的MVC项目,创建完成之后我们运行一下(Ctrl +F5).我们会在页面上看到"He ...

  2. 从零开始构建一个的asp.net Core 项目(一)

    最近突发奇想,想从零开始构建一个Core的MVC项目,于是开始了构建过程. 首先我们添加一个空的CORE下的MVC项目,创建完成之后我们运行一下(Ctrl +F5).我们会在页面上看到“Hello W ...

  3. 不借助vue-cli,自行构建一个vue项目

    前言: 对于刚刚接触vue的同学来说,直接用官方的构建工具vue-cli来生成一个项目结构会存在一些疑惑,比如:   .vue组件 为什么可以写成三段式(tempalte.script.style)? ...

  4. 从实体框架核心开始:构建一个ASP。NET Core应用程序与Web API和代码优先开发

    下载StudentApplication.Web.zip - 599.5 KB 下载StudentApplication.API.zip - 11.5 KB 介绍 在上一篇文章中,我们了解了实体框架的 ...

  5. 《Entity Framework 6 Recipes》中文翻译系列 (20) -----第四章 ASP.NET MVC中使用实体框架之在MVC中构建一个CRUD示例

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第四章  ASP.NET MVC中使用实体框架 ASP.NET是一个免费的Web框架 ...

  6. 从零构建一个简单的 Python Web框架

    为什么你想要自己构建一个 web 框架呢?我想,原因有以下几点: 你有一个新奇的想法,觉得将会取代其他的框架 你想要获得一些名气 你遇到的问题很独特,以至于现有的框架不太合适 你对 web 框架是如何 ...

  7. 抛弃EF,20分构建一个属于自己的ORM框架

    Poiuyt_cyc 博客园首页新随笔联系订阅管理随笔 - 11  文章 - 0  评论 - 111 抛弃EF,20分构建一个属于自己的ORM框架 相信EF大家都不陌生了,因为数据库表跟程序实体是一一 ...

  8. 构建NetCore应用框架之实战篇(一):什么是框架,如何设计一个框架

    一.系列简述 本篇起,将通过一系列文章,去描述如何构建一个应用开发框架,并以作者开发的框架为例,逐个点展开分析,如何从零开始,构建自己的开发框架. 本系列文章的目的,是带领有一编程经验的人,通过动手, ...

  9. 如何在Visual Studio 2017中使用C# 7+语法 构建NetCore应用框架之实战篇(二):BitAdminCore框架定位及架构 构建NetCore应用框架之实战篇系列 构建NetCore应用框架之实战篇(一):什么是框架,如何设计一个框架 NetCore入门篇:(十二)在IIS中部署Net Core程序

    如何在Visual Studio 2017中使用C# 7+语法   前言 之前不知看过哪位前辈的博文有点印象C# 7控制台开始支持执行异步方法,然后闲来无事,搞着,搞着没搞出来,然后就写了这篇博文,不 ...

随机推荐

  1. JavaScript中的闭包永远都存储在内存中,除非关闭浏览器

    //閉包實現累加功能 function fn1() { var n = 1; add = function() { n += 1; } function fn2() { n += 1; console ...

  2. 20175316 盛茂淞 MyCP(课下作业,必做)

    题目要求 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt XXX2.bin 用来把文本文件(内容为 ...

  3. 第二周工作总结——NWNU李泓毅

    注:因作业未全部提交完毕,故评分细则和千帆图等评分事项推后 1.助教博客链接:https://www.cnblogs.com/lmcmha/ 2.本周点评作业: https://www.cnblogs ...

  4. 接口约束的另一种方法:Class类的isAssignableFrom

    Class类的isAssignableFrom是个不常用的方法,感觉这个方法的名字取得不是很好,所以有必要在此解析一下,以免在看源码时产生歧义,这个方法的签名如下: public native boo ...

  5. Linux---设备文件名和挂载点

    分区: 1.分区: MBR   GPT 2.格式化  : 为了写入文件系统 3.设备文件名 4.什么是挂载点? 挂载点:使用已经存在的空目录作为挂载点 挂载: 必须分区: / (根分区) swap分区 ...

  6. CentOS 7 nginx 1.8.1安装

    OS版本:CentOS 7.2nginx版本:1.8.1所需包:openssl-1.0.2m.tar.gz zlib-1.2.8.tar.gz pcre-8.36.tar.gz nginx-1.8.1 ...

  7. Java 输入流(一)ByteArrayInputStream

    概述 ByteArrayInputStream类是从内存中的字节数组中读取数据,因此它的数据源是一个字节数组.

  8. 与我们息息相关的internet服务(3)---电子邮件服务

    几年前了解了一下,现在再实施的时候,再了解,当然如果要到牛人张小龙28岁时的开发程度,可能还差一个筋斗云 在起步一个公司,从组建的技术上,可能要准备很多东西,其中一个就是我们熟悉的企业邮箱. 伊妹儿, ...

  9. Servlet映射

    转载自https://blog.csdn.net/xinluke/article/details/51449594 映射请求到Servlet |-- Context Path --|-- Servle ...

  10. 0723掰棒子记录--vue的数据渲染

    问题1:想要在一个panel标签中添加一个图片,panel中有一个datalist属性.如何设计标签可以插入想要的图片. template: <panel :list="dataLis ...