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. 總結
在這一篇帶領大家梳理了一下資料訪問的介面定義,對一個系統來說,這些方法都是有必要的(但不是每個方法使用頻率都一樣高),也是簡單的跟大家分享一下我在實際作業中寫代碼的總結,
更多內容煩請關注我的博客《高先生小屋》

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/20461.html
標籤:C#
上一篇:C#基礎篇——委托
下一篇:C#中的泛型
