【asp.net core】7 實(shí)戰(zhàn)之 數(shù)據(jù)訪問(wèn)層定義

0. 前言

在上一篇磅摹,我們搭建了一個(gè)項(xiàng)目框架,基本上是一個(gè)完整的項(xiàng)目霎奢。目前而言户誓,大部分的應(yīng)用基本都是這個(gè)結(jié)構(gòu)。好的幕侠,不廢話了帝美,進(jìn)入今天的議題:完成并實(shí)現(xiàn)數(shù)據(jù)層的基礎(chǔ)實(shí)現(xiàn)。

1. 數(shù)據(jù)實(shí)體

通常情況下晤硕,一個(gè)項(xiàng)目的數(shù)據(jù)實(shí)體中字段并不是完全沒(méi)有規(guī)律可尋悼潭。通常情況下,必須有一個(gè)主鍵窗骑。有些時(shí)候女责,會(huì)要求在數(shù)據(jù)表中增加上次修改時(shí)間和創(chuàng)建時(shí)間漆枚,以及創(chuàng)建人和修改人的主鍵创译。

所以,我們可以創(chuàng)建一個(gè)泛型父類墙基,來(lái)幫我們定義這些公共字段:

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里。這個(gè)命名空間 Infrastructure 用來(lái)存放一些項(xiàng)目的架構(gòu)類或者接口立砸,里面還會(huì)其他的類掖疮。

那么,給這個(gè)類補(bǔ)充一些可能有用的方法:

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;
}

這里用來(lái)保存用戶ID的字段颗祝,我都用了字符串做保存浊闪,是借用字符串類型保存數(shù)據(jù)時(shí)能容納更多的數(shù)據(jù)類型。

2. 常見(jiàn)數(shù)據(jù)操作接口

在正常開(kāi)發(fā)中螺戳,一個(gè)完整的數(shù)據(jù)操作接口會(huì)有很多分類搁宾,但是很多時(shí)候我們需要分開(kāi)增刪改和查詢這兩種操作。對(duì)于數(shù)據(jù)庫(kù)而言倔幼,視圖和有些數(shù)據(jù)表都是不被允許改變的盖腿,這時(shí)候就需要我們只對(duì)調(diào)用方開(kāi)放查詢接口,而不開(kāi)放修改接口损同。

所以翩腐,在Domain下應(yīng)該有以下兩個(gè)接口:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace Domain.Infrastructure
{
    /// <summary>
    /// 修改接口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IModifyRepository<T>
    {
        /// <summary>
        /// 插入數(shù)據(jù)
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        T Insert(T entity);
        /// <summary>
        /// 插入數(shù)據(jù)
        /// </summary>
        /// <param name="entities"></param>
        void Insert(params T[] entities);
        /// <summary>
        /// 插入數(shù)據(jù)
        /// </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>
        /// 更新數(shù)據(jù)
        /// </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>
        /// 刪除數(shù)據(jù)
        /// </summary>
        /// <param name="entities"></param>
        void Delete(params T[] entities);
        /// <summary>
        /// 根據(jù)條件刪除數(shù)據(jù)
        /// </summary>
        /// <param name="predicate"></param>
        void Delete(Expression<Func<T,bool>> predicate);
        /// <summary>
        /// 刪除主鍵對(duì)應(yīng)的數(shù)據(jù)
        /// </summary>
        /// <param name="key"></param>
        void DeleteByKey(object key);
        /// <summary>
        /// 刪除主鍵對(duì)應(yīng)的數(shù)據(jù)
        /// </summary>
        /// <param name="keys"></param>
        void DeleteByKeys(params object[] keys);       
    }
}

上述是更新接口,那么我們回過(guò)頭來(lái)寫(xiě)查詢接口膏燃,查詢接口的方法有很多茂卦。我們先創(chuàng)建一個(gè)接口文件:

using System;
using System.Linq.Expressions;

namespace Domain.Infrastructure
{
    /// <summary>
    /// 查詢接口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface ISearchRepository<T>
    {
        
    }
}

一個(gè)查詢接口應(yīng)該包括以下方法:

  • 獲取單個(gè)數(shù)據(jù)
/// <summary>
/// 根據(jù)主鍵獲取數(shù)據(jù)
/// </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);
  • 統(tǒng)計(jì)數(shù)量:
/// <summary>
/// 返回?cái)?shù)據(jù)庫(kù)中的數(shù)據(jù)條目
/// </summary>
/// <returns></returns>
int Count();
/// <summary>
/// 返回?cái)?shù)據(jù)庫(kù)中的數(shù)據(jù)條目,類型為L(zhǎng)ong
/// </summary>
/// <returns></returns>
long LongCount();
/// <summary>
/// 返回符合條件的數(shù)據(jù)數(shù)目
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
int Count(Expression<Func<T,bool>> predicate);
/// <summary>
/// 返回長(zhǎng)整形的符合條件的數(shù)目
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
long LongCount(Expression<Func<T,bool>> predicate);
  • 存在性判斷
/// <summary>
/// 是否存在滿足條件的數(shù)據(jù)
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
bool IsExists(Expression<Func<T, bool>> predicate);
  • 查詢
// <summary>
/// 返回?cái)?shù)據(jù)庫(kù)中所有記錄
/// </summary>
/// <returns></returns>
List<T> Search();
/// <summary>
/// 返回所有符合條件的數(shù)據(jù)
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
List<T> Search(Expression<Func<T,bool>> predicate);
/// <summary>
/// 返回一個(gè)延遲查詢的對(duì)象
/// </summary>
/// <returns></returns>
IEnumerable<T> Query();
/// <summary>
/// 返回一個(gè)延遲查詢的對(duì)象组哩,并預(yù)設(shè)了一個(gè)查詢條件
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
IEnumerable<T> Query(Expression<Func<T,bool>> predicate);
  • 排序
/// <summary>
/// 排序查詢疙筹,默認(rèn)升序
/// </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);
  • 分頁(yè)

實(shí)際上分頁(yè)的接口定義模型需要兩個(gè)類的輔助禁炒,如果沒(méi)有這兩個(gè)類而咆,接口的定義會(huì)變得十分復(fù)雜,不利于代碼的可讀性:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace Data.Infrastructure
{
    /// <summary>
    /// 分頁(yè)條件模型
    /// </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>
        /// 升序排序或者降序排序幕袱,升序?yàn)?asc或者空暴备,降序?yàn)閐esc
        /// </summary>
        /// <value></value>
        public string Sort{get;set;}
        /// <summary>
        /// 每頁(yè)最大數(shù)據(jù)容量
        /// </summary>
        /// <value></value>
        public int PerpageSize { get; set; }
        /// <summary>
        /// 當(dāng)前頁(yè)
        /// </summary>
        /// <value></value>
        public int CurrentPage { get; set; }
    }
    /// <summary>
    /// 分頁(yè)結(jié)果
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class PageModel<T>
    {
        /// <summary>
        /// 數(shù)據(jù)
        /// </summary>
        /// <value></value>
        public List<T> Items { get; set; }
        /// <summary>
        /// 當(dāng)前頁(yè)碼
        /// </summary>
        /// <value></value>
        public int CurrentPage { get; set; }
        /// <summary>
        /// 每頁(yè)最大數(shù)據(jù)容量
        /// </summary>
        /// <value></value>
        public int PerpageSize { get; set; }
        /// <summary>
        /// 查詢數(shù)據(jù)總數(shù)
        /// </summary>
        /// <value></value>
        public long TotalCount { get; set; }
        /// <summary>
        /// 總頁(yè)碼
        /// </summary>
        /// <value></value>
        public int TotalPages { get; set; }
    }
}

這是兩個(gè)輔助類,可以簡(jiǎn)單看一下如果這些參數(shù)不進(jìn)行封裝直接傳給方法们豌,可以預(yù)見(jiàn)方法的參數(shù)列表會(huì)特別長(zhǎng)涯捻,這對(duì)于可讀性和可維護(hù)性來(lái)說(shuō)簡(jiǎn)直就是災(zāi)難。我曾經(jīng)接手過(guò)一個(gè)項(xiàng)目的維護(hù)望迎,上一位開(kāi)發(fā)者在一個(gè)方法寫(xiě)了近15個(gè)參數(shù)障癌,而且還有大量的可選參數(shù),嗯辩尊,十分頭疼涛浙。所以,我不建議大家這樣寫(xiě),一個(gè)方法參數(shù)超過(guò)4個(gè)我建議還是封裝一下轿亮。

那么疮薇,看一看方法的聲明:

/// <summary>
/// 根據(jù)分頁(yè)參數(shù)設(shè)置,進(jìn)行分頁(yè)查詢
/// </summary>
/// <param name="condition"></param>
/// <returns></returns>
PageModel<T> Search(PageCondition<T> condition);

這是使用參數(shù)封裝了請(qǐng)求的寫(xiě)法我注,小伙伴們可以試試不用封裝按咒,方法是如何聲明的。

3. 總結(jié)

在這一篇帶領(lǐng)大家梳理了一下數(shù)據(jù)訪問(wèn)的接口定義但骨,對(duì)一個(gè)系統(tǒng)來(lái)說(shuō)励七,這些方法都是有必要的(但不是每個(gè)方法使用頻率都一樣高)。也是簡(jiǎn)單的跟大家分享一下我在實(shí)際工作中寫(xiě)代碼的總結(jié)奔缠。

更多內(nèi)容煩請(qǐng)關(guān)注我的博客《高先生小屋》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末呀伙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子添坊,更是在濱河造成了極大的恐慌剿另,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贬蛙,死亡現(xiàn)場(chǎng)離奇詭異雨女,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)阳准,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門氛堕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人野蝇,你說(shuō)我怎么就攤上這事讼稚。” “怎么了绕沈?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵锐想,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我乍狐,道長(zhǎng)赠摇,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任浅蚪,我火速辦了婚禮藕帜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惜傲。我一直安慰自己洽故,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布盗誊。 她就那樣靜靜地躺著时甚,像睡著了一般隘弊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上撞秋,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天长捧,我揣著相機(jī)與錄音嚣鄙,去河邊找鬼吻贿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛哑子,可吹牛的內(nèi)容都是我干的舅列。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼卧蜓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼帐要!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起弥奸,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤榨惠,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后盛霎,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體赠橙,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年愤炸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了期揪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡规个,死狀恐怖凤薛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诞仓,我是刑警寧澤缤苫,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站墅拭,受9級(jí)特大地震影響榨馁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帜矾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一翼虫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屡萤,春花似錦珍剑、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)唧瘾。三九已至,卻和暖如春别凤,著一層夾襖步出監(jiān)牢的瞬間饰序,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工规哪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留求豫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓诉稍,卻偏偏與公主長(zhǎng)得像蝠嘉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子杯巨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355