温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

asp.net core中怎么定义数据访问层

发布时间:2021-07-15 14:20:50 阅读:200 作者:Leah 栏目:大数据
开发者测试专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

asp.net core中怎么定义数据访问层,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

1. 数据实体

通常情况下,一个项目的数据实体中字段并不是完全没有规律可寻。通常情况下,必须有一个主键。有些时候,会要求在数据表中增加上次修改时间和创建时间,以及创建人和修改人的主键。

所以,我们可以创建一个泛型父类,来帮我们定义这些公共字段:

using System;namespace Data.Infrastructure{    public class BaseEntity<T>    {        public T Id { get; set; }        public string ModifyUserId { get; set; }        public DateTime? ModifyTime { get; set; }        public string CreatorId { get; set; }        public DateTime? CreateTime { get; set; }    }}
 

看上述代码里,命名空间并不在Data里,而是在Data.Infrastructure里。这个命名空间 Infrastructure 用来存放一些项目的架构类或者接口,里面还会其他的类。

那么,给这个类补充一些可能有用的方法:

public void Create(object userId){    CreatorId = userId.ToString();    CreateTime = DateTime.Now;}public void Create(object userId, DateTime createTime){    CreatorId = userId.ToString();    CreateTime = createTime;}public void Modify(object userId){    ModifyUserId = userId.ToString();    ModifyTime = DateTime.Now;}public void Modify(object userId, DateTime modifyTime){    ModifyUserId = userId.ToString();    ModifyTime = modifyTime;}
 

这里用来保存用户ID的字段,我都用了字符串做保存,是借用字符串类型保存数据时能容纳更多的数据类型。

 

2. 常见数据操作接口

在正常开发中,一个完整的数据操作接口会有很多分类,但是很多时候我们需要分开增删改和查询这两种操作。对于数据库而言,视图和有些数据表都是不被允许改变的,这时候就需要我们只对调用方开放查询接口,而不开放修改接口。

所以,在Domain下应该有以下两个接口:

using System;using System.Collections.Generic;using System.Linq.Expressions;namespace Domain.Infrastructure{    /// <summary>    /// 修改接口    /// </summary>    /// <typeparam name="T"></typeparam>    public interface IModifyRepository<T>    {        /// <summary>        /// 插入数据        /// </summary>        /// <param name="entity"></param>        /// <returns></returns>        T Insert(T entity);        /// <summary>        /// 插入数据        /// </summary>        /// <param name="entities"></param>        void Insert(params T[] entities);        /// <summary>        /// 插入数据        /// </summary>        /// <param name="entities"></param>        void Insert(IEnumerable<T> entities);        /// <summary>        /// 保存已提交的修改        /// </summary>        /// <param name="entity"></param>        void Update(T entity);        /// <summary>        /// 保存已提交的修改        /// </summary>        /// <param name="entities"></param>        void Update(params T[] entities);        /// <summary>        /// 更新数据        /// </summary>        /// <param name="predicate"></param>        /// <param name="updator"></param>        void Update(Expression<Func<T, bool>> predicate, Expression<Func<T, T>> updator);        /// <summary>        /// 删除        /// </summary>        /// <param name="entity"></param>        void Delete(T entity);        /// <summary>        /// 删除数据        /// </summary>        /// <param name="entities"></param>        void Delete(params T[] entities);        /// <summary>        /// 根据条件删除数据        /// </summary>        /// <param name="predicate"></param>        void Delete(Expression<Func<T,bool>> predicate);        /// <summary>        /// 删除主键对应的数据        /// </summary>        /// <param name="key"></param>        void DeleteByKey(object key);        /// <summary>        /// 删除主键对应的数据        /// </summary>        /// <param name="keys"></param>        void DeleteByKeys(params object[] keys);    }}
 

上述是更新接口,那么我们回过头来写查询接口,查询接口的方法有很多。我们先创建一个接口文件:

using System;using System.Linq.Expressions;namespace Domain.Infrastructure{    /// <summary>    /// 查询接口    /// </summary>    /// <typeparam name="T"></typeparam>    public interface ISearchRepository<T>    {    }}
 

一个查询接口应该包括以下方法:

  • 获取单个数据

/// <summary>/// 根据主键获取数据/// </summary>/// <param name="key"></param>/// <returns></returns>T Get(object key);/// <summary>/// 查询/// </summary>/// <param name="predicate"></param>/// <returns></returns>T Get(Expression<Func<T,bool>> predicate);
 
  • 统计数量:

/// <summary>/// 返回数据库中的数据条目/// </summary>/// <returns></returns>int Count();/// <summary>/// 返回数据库中的数据条目,类型为Long/// </summary>/// <returns></returns>long LongCount();/// <summary>/// 返回符合条件的数据数目/// </summary>/// <param name="predicate"></param>/// <returns></returns>int Count(Expression<Func<T,bool>> predicate);/// <summary>/// 返回长整形的符合条件的数目/// </summary>/// <param name="predicate"></param>/// <returns></returns>long LongCount(Expression<Func<T,bool>> predicate);
 
  • 存在性判断

/// <summary>/// 是否存在满足条件的数据/// </summary>/// <param name="predicate"></param>/// <returns></returns>bool IsExists(Expression<Func<T, bool>> predicate);
 
  • 查询

// <summary>/// 返回数据库中所有记录/// </summary>/// <returns></returns>List<T> Search();/// <summary>/// 返回所有符合条件的数据/// </summary>/// <param name="predicate"></param>/// <returns></returns>List<T> Search(Expression<Func<T,bool>> predicate);/// <summary>/// 返回一个延迟查询的对象/// </summary>/// <returns></returns>IEnumerable<T> Query();/// <summary>/// 返回一个延迟查询的对象,并预设了一个查询条件/// </summary>/// <param name="predicate"></param>/// <returns></returns>IEnumerable<T> Query(Expression<Func<T,bool>> predicate);
 
  • 排序

/// <summary>/// 排序查询,默认升序/// </summary>/// <param name="predicate"></param>/// <param name="order"></param>/// <typeparam name="P"></typeparam>/// <returns></returns>List<T> Search<P>(Expression<Func<T, bool>> predicate, Expression<Func<T, P>> order);/// <summary>/// 排序查找,指定是否降序排列/// </summary>/// <param name="predicate"></param>/// <param name="order"></param>/// <param name="isDesc"></param>/// <typeparam name="P"></typeparam>/// <returns></returns>List<T> Search<P>(Expression<Func<T, bool>> predicate, Expression<Func<T, P>> order, bool isDesc);
 
  • 分页

实际上分页的接口定义模型需要两个类的辅助,如果没有这两个类,接口的定义会变得十分复杂,不利于代码的可读性:

using System;using System.Collections.Generic;using System.Linq.Expressions;namespace Data.Infrastructure{    /// <summary>    /// 分页条件模型    /// </summary>    /// <typeparam name="T"></typeparam>    public class PageCondition<T>    {        /// <summary>        /// 查询条件        /// </summary>        /// <value></value>        public Expression<Func<T, bool>> Predicate { get; set; }        /// <summary>        /// 排序字段        /// </summary>        /// <value></value>        public string OrderProperty { get; set; }        /// <summary>        /// 升序排序或者降序排序,升序为 asc或者空,降序为desc        /// </summary>        /// <value></value>        public string Sort{get;set;}        /// <summary>        /// 每页最大数据容量        /// </summary>        /// <value></value>        public int PerpageSize { get; set; }        /// <summary>        /// 当前页        /// </summary>        /// <value></value>        public int CurrentPage { get; set; }    }    /// <summary>    /// 分页结果    /// </summary>    /// <typeparam name="T"></typeparam>    public class PageModel<T>    {        /// <summary>        /// 数据        /// </summary>        /// <value></value>        public List<T> Items { get; set; }        /// <summary>        /// 当前页码        /// </summary>        /// <value></value>        public int CurrentPage { get; set; }        /// <summary>        /// 每页最大数据容量        /// </summary>        /// <value></value>        public int PerpageSize { get; set; }        /// <summary>        /// 查询数据总数        /// </summary>        /// <value></value>        public long TotalCount { get; set; }        /// <summary>        /// 总页码        /// </summary>        /// <value></value>        public int TotalPages { get; set; }    }}
 

这是两个辅助类,可以简单看一下如果这些参数不进行封装直接传给方法,可以预见方法的参数列表会特别长,这对于可读性和可维护性来说简直就是灾难。我曾经接手过一个项目的维护,上一位开发者在一个方法写了近15个参数,而且还有大量的可选参数,嗯,十分头疼。所以,我不建议大家这样写,一个方法参数超过4个我建议还是封装一下。

那么,看一看方法的声明:

/// <summary>/// 根据分页参数设置,进行分页查询/// </summary>/// <param name="condition"></param>/// <returns></returns>PageModel<T> Search(PageCondition<T> condition);

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:https://my.oschina.net/c7jie/blog/4487127

AI

开发者交流群×