# 业务数据层

# 概述

一个模块的数据层,主要包括如下几个方面:

  • 数据实体:数据实体是服务层向数据库进行数据持久化的数据载体,也是数据层进行业务处理的数据载体,数据层与数据层的数据交换都应通过实体类来完成。

  • 输入DTO:InputDto用于前端向API层输入数据,API层向服务层输入数据

  • 输出DTO:OutputDto主要用于数据查询服务,是API层向前端输出数据的载体

  • 数据实体映射配置:DBFirst的开发模式,数据库的设计优先完成,数据实体映射配置正是负责这项工作的,针对一个实体,可以在这里配置其在数据库中的数据表关系、数据约束及各个数据字段的每一个细节配置。

  • 对象Mapper映射:数据传输对象DTO 与 实体类Entity 之间的转换与更新,如果都要通过手写代码来进行属性的一一对应赋值,是件很累人的事,通过 对象Mapper映射(例如AutoMapper)功能,只需进行一次配置,即可很方便的实现不同类型对象的数据转换与更新。

# 数据层文件夹结构

src                                     # 源代码文件夹
└─Yuebon.Security.Core                  # 项目核心工程
     ├─Dtos                             # 业务单据编码模块DTO文件夹
     │    ├─SequenceInputDto.cs         # 业务单据输入DTO
     │    ├─SequenceOutputDto.cs        # 业务单据输出入DTO
     │    ├─SequenceRuleInputDto.cs     # 单据编码规则输入DTO
     │    └─SequenceRuleOutputDto.cs    # 单据编码规则输出DTO
     └─Models                           # 业务单据编码模块实体类文件夹
     │    ├─Sequence.cs                 # 业务单据实体类
     │    └─SequenceRule.cs             # 单据编码规则实体类
     └─IRepositories                    # 业务单据编码模块仓储接口文件夹
     │    ├─ISequenceRepository.cs      # 业务单据仓储接口类
     │    └─ISequenceRuleRepository.cs   # 单据编码规则仓储接口类
     └─Repositories                     # 业务单据编码模块实体类文件夹
          ├─SequenceRepository.cs       # 业务单据仓储接口实现类
          └─SequenceRuleRepository.cs   # 单据编码规则仓储接口实现类

# 实体

# 实体基类Entity

所有数据库实体必须继承Entity实体基类

BaseEntity实体是预定义实体,系统默认的主键是以Id命名,业务实体中将继承BaseEntity基类即可.

# 可选接口与特性

创建审计信息ICreationAudited接口、更新审计的信息IModificationAudited接口、逻辑删除功能审计信息IDeleteAudited接口

更多关于实体的描述参见数据库实体

综合代码如何:

/// <summary>
/// 单据编码,数据实体对象
/// </summary>
[Table("Sys_Sequence")]
[Serializable]
public class Sequence:BaseEntity<string>, ICreationAudited, IModificationAudited, IDeleteAudited
{
    /// <summary>
    /// 设置或获取名称
    /// </summary>
    public string SequenceName { get; set; }

    /// <summary>
    /// 设置或获取分隔符
    /// </summary>
    public string SequenceDelimiter { get; set; }

    /// <summary>
    /// 设置或获取序号重置规则
    /// </summary>
    public string SequenceReset { get; set; }

    /// <summary>
    /// 设置或获取步长
    /// </summary>
    public int Step { get; set; }

    /// <summary>
    /// 设置或获取当前值
    /// </summary>
    public int CurrentNo { get; set; }

    /// <summary>
    /// 设置或获取当前编码
    /// </summary>
    public string CurrentCode { get; set; }

    /// <summary>
    /// 设置或获取当前重置依赖
    /// </summary>
    public string CurrentReset { get; set; }

    /// <summary>
    /// 设置或获取 
    /// </summary>
    public string Description { get; set; }

    /// <summary>
    /// 设置或获取是否可用
    /// </summary>
    public bool? EnabledMark { get; set; }

    /// <summary>
    /// 设置或获取删除标记
    /// </summary>
    public bool? DeleteMark { get; set; }

    /// <summary>
    /// 设置或获取创建时间
    /// </summary>
    public DateTime? CreatorTime { get; set; }

    /// <summary>
    /// 设置或获取创建人
    /// </summary>
    public string CreatorUserId { get; set; }

    /// <summary>
    /// 设置或获取创建人组织
    /// </summary>
    public string CompanyId { get; set; }

    /// <summary>
    /// 设置或获取部门
    /// </summary>
    public string DeptId { get; set; }

    /// <summary>
    /// 设置或获取修改时间
    /// </summary>
    public DateTime? LastModifyTime { get; set; }

    /// <summary>
    /// 设置或获取修改人
    /// </summary>
    public string LastModifyUserId { get; set; }

    /// <summary>
    /// 设置或获取删除时间
    /// </summary>
    public DateTime? DeleteTime { get; set; }

    /// <summary>
    /// 设置或获取删除人
    /// </summary>
    public string DeleteUserId { get; set; }
}

# 输入输出DTO

输入输出DTO:输入输出DTO主要负责各层次之间的数据传输工作,避免在外层暴露实体类。

1、输入实体:

/// <summary>
/// 单据编码输入对象模型
/// </summary>
[AutoMap(typeof(Sequence))]
[Serializable]
public class SequenceInputDto: IInputDto<string>
{
    /// <summary>
    /// 设置或获取 
    /// </summary>
    public string Id { get; set; }

    /// <summary>
    /// 设置或获取名称
    /// </summary>
    public string SequenceName { get; set; }

    /// <summary>
    /// 设置或获取分隔符
    /// </summary>
    public string SequenceDelimiter { get; set; }

    /// <summary>
    /// 设置或获取序号重置规则
    /// </summary>
    public string SequenceReset { get; set; }

    /// <summary>
    /// 设置或获取步长
    /// </summary>
    public int Step { get; set; }

    /// <summary>
    /// 设置或获取当前值
    /// </summary>
    public int CurrentNo { get; set; }

    /// <summary>
    /// 设置或获取当前编码
    /// </summary>
    public string CurrentCode { get; set; }

    /// <summary>
    /// 设置或获取当前重置依赖
    /// </summary>
    public string CurrentReset { get; set; }

    /// <summary>
    /// 设置或获取 
    /// </summary>
    public string Description { get; set; }

    /// <summary>
    /// 设置或获取是否可用
    /// </summary>
    public bool? EnabledMark { get; set; }
}

2、输出实体

/// <summary>
/// 单据编码输出对象模型
/// </summary>
[Serializable]
public class SequenceOutputDto
{
    /// <summary>
    /// 设置或获取 
    /// </summary>
    [MaxLength(50)]
    public string Id { get; set; }

    /// <summary>
    /// 设置或获取名称
    /// </summary>
    [MaxLength(50)]
    public string SequenceName { get; set; }

    /// <summary>
    /// 设置或获取分隔符
    /// </summary>
    [MaxLength(50)]
    public string SequenceDelimiter { get; set; }

    /// <summary>
    /// 设置或获取序号重置规则
    /// </summary>
    [MaxLength(50)]
    public string SequenceReset { get; set; }

    /// <summary>
    /// 设置或获取步长
    /// </summary>
    public int Step { get; set; }

    /// <summary>
    /// 设置或获取当前值
    /// </summary>
    public int CurrentNo { get; set; }

    /// <summary>
    /// 设置或获取当前编码
    /// </summary>
    [MaxLength(200)]
    public string CurrentCode { get; set; }

    /// <summary>
    /// 设置或获取当前重置依赖
    /// </summary>
    [MaxLength(50)]
    public string CurrentReset { get; set; }

    /// <summary>
    /// 设置或获取 
    /// </summary>
    [MaxLength(200)]
    public string Description { get; set; }

    /// <summary>
    /// 设置或获取是否可用
    /// </summary>
    public bool? EnabledMark { get; set; }

    /// <summary>
    /// 设置或获取删除标记
    /// </summary>
    public bool? DeleteMark { get; set; }

    /// <summary>
    /// 设置或获取创建时间
    /// </summary>
    public DateTime? CreatorTime { get; set; }

    /// <summary>
    /// 设置或获取创建人
    /// </summary>
    [MaxLength(50)]
    public string CreatorUserId { get; set; }

    /// <summary>
    /// 设置或获取创建人组织
    /// </summary>
    [MaxLength(50)]
    public string CompanyId { get; set; }

    /// <summary>
    /// 设置或获取部门
    /// </summary>
    [MaxLength(50)]
    public string DeptId { get; set; }

    /// <summary>
    /// 设置或获取修改时间
    /// </summary>
    public DateTime? LastModifyTime { get; set; }

    /// <summary>
    /// 设置或获取修改人
    /// </summary>
    [MaxLength(50)]
    public string LastModifyUserId { get; set; }

    /// <summary>
    /// 设置或获取删除时间
    /// </summary>
    public DateTime? DeleteTime { get; set; }

    /// <summary>
    /// 设置或获取删除人
    /// </summary>
    [MaxLength(50)]
    public string DeleteUserId { get; set; }


}

# 仓储

IRepository、BaseRepository是仓储接口和实现基类,所有业务模块的仓储类都继承该基类。

# 1、仓储接口

所有业务的Repository接口必须继承IRepository基础接口。主要用于定义业务自己的功能业务接口,不要与IRepository接口名称一致即可。

/// <summary>
/// 定义单据编码仓储接口
/// </summary>
public interface ISequenceRepository:IRepository<Sequence, string>
{
}

# 2、仓储接口的实现

1、主要实现仓储接口中定义方法实现,同时对BaseRepository中的方法实现不能满足业务需要时可以重写相关的方法。

2、此处需根据业务情况依赖注入服务生命周期接口。

IScopedDependency:对应请求作用域服务生存期。在同一个作用域内只初始化一个实例 ,可以理解为每一个请求只创建一个实例,同一个请求会在一个作用域内。在Scooped的生存周期内,如果容器释放 它也就被释放了。

ISingletonDependency:对应单例作用域服务生存期。整个应用程序生命周期以内只创建一个实例,后续每个请求都使用相同的实例。如果应用程序需要单例行为,建议让服务容器管理服务的生命周期,而不是在自己的类中实现单例模式。

ITransientDependency:对应暂时/瞬时作用域服务生存期。针对每一次服务提供请求,创建一个新的服务实例。

重要提示

以上三个接口只能实例类实现,其他静态类、抽象类、及接口不能实现。

如果没有依赖注入服务生命周期接口,在注入服务时默认为ITransient对应暂时/瞬时作用域服务生存期。

/// <summary>
/// 单据编码仓储接口的实现
/// </summary>
public class SequenceRepository : BaseRepository<Sequence, string>, ISequenceRepository,ITransientDependency
{
    public SequenceRepository()
    {
    }

    public SequenceRepository(IDbContextCore dbContext) : base(dbContext)
    {
    }
}

如遇到问题到Issues(opens new window) 反馈