【asp.net core】7 實戰之 數據訪問層定義

来源:https://www.cnblogs.com/c7jie/archive/2020/06/07/13061127.html
-Advertisement-
Play Games

0. 前言 在上一篇,我們搭建了一個項目框架,基本上是一個完整的項目。目前而言,大部分的應用基本都是這個結構。好的,不廢話了,進入今天的議題:完成並實現數據層的基礎實現。 1. 數據實體 通常情況下,一個項目的數據實體中欄位並不是完全沒有規律可尋。通常情況下,必須有一個主鍵。有些時候,會要求在數據表 ...


0. 前言

在上一篇,我們搭建了一個項目框架,基本上是一個完整的項目。目前而言,大部分的應用基本都是這個結構。好的,不廢話了,進入今天的議題:完成並實現數據層的基礎實現。

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

這是使用參數封裝了請求的寫法,小伙伴們可以試試不用封裝,方法是如何聲明的。

3. 總結

在這一篇帶領大家梳理了一下數據訪問的介面定義,對一個系統來說,這些方法都是有必要的(但不是每個方法使用頻率都一樣高)。也是簡單的跟大家分享一下我在實際工作中寫代碼的總結。

更多內容煩請關註我的博客《高先生小屋》

file


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • IDEA下一個簡單的mybaties測試程式,適合初學者閱讀。 目錄結構及lib: 在src>main>java 下 根據資料庫表創建實體類:com.itheima.domain.User 註意:表欄位名和實體屬性要對應一致 package com.itheima.domain; import ja ...
  • 今天整理了下,springboot下單元測試基本用法 若使用了 @RunWith(SpringRunner.class)配置,需要用 org.junit.Test運行,juint4包, junit5包org.junit.jupiter.api.Test 不需要RunWith註解. 一 引入依賴 1 ...
  • 有時候不得不感慨一下,系統升級真的是好處多多,不僅讓我有機會重構了之前的爛代碼,也滿足了我積極好學的虛榮心。你看,Redis 入門了、Elasticsearch 入門了,這次又要入門 MongoDB,感覺自己變禿的同時,也變強大了。 小伙伴們在繼續閱讀之前,我必須要聲明一點,我對 MongoDB 並 ...
  • 聚合就是歸類的意思,把同類事物統一處理; 聚合根也就是最抽象,最普遍的特性; 背景 領域建模的過程回顧: 那麼問題來了? 為什麼要在限界上下文和實體之間增加聚合和聚合根的概念,即作用是什麼? 如何設計聚合? 按照一般的研究和學習思路,先弄懂概念,然後結合實際例子理解概念,然後再回答提出的問題。 聚合 ...
  • 1 第一單元 常用標準包(一) 2 3 1.學習目標 4 5 1. 掌握strings常用函數使用 6 2. 掌握strconv常用函數使用 7 3. 熟悉encoding常用函數使用 8 9 2.strings標準包 10 11 2.1 Contains 12 13 用途:字元串包含關係 14 1 ...
  • Auto.js是什麼 安卓腳本框架 可以做的事情 數據監控:可以監視當前手機的數據。 圖片監控:截圖獲取當前頁面信息。 控制項操作:模擬操作手機控制項。 自動化工作流:編寫簡單的腳本,完成一系列自動化操作。如:微信自動點贊,快速搶單等。 定時功能:定時執行某個腳本,來完成定時任務。如:定時打卡簽到等。 ...
  • 前言 在JAVA虛擬機記憶體管理中,堆、棧、方法區、常量池等概念經常被提到,對理論知識的理解也常常停留在字面意思上,比如說堆記憶體中存放對象,棧記憶體中存放局部變數,常量池中存放字元串常量表等,本篇文章通過一個有趣的例子,儘量將這些理論概念通過程式樣例及圖解的方式表達清楚,讓我們更能深入底層知識。 例子 ...
  • 前言 在ASP.NET Core中最大的更改之一是對Http請求管道的更改,在ASP.NET中我們瞭解HttpHandler和HttpModule但是到現在這些已經被替換為中間件那麼下麵我們來看一下他們的不同處。 HttpHandler Handlers處理基於擴展的特定請求,HttpHandler ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...