C# 輕量級系統基礎架構 (MVP MEF + EF6)

来源:https://www.cnblogs.com/sam-snow-v/archive/2019/02/21/10405435.html
-Advertisement-
Play Games

0 綜述 1 MVP各模塊規範 1.1 實體模塊規範 1.1.1 命名規範 實體類封裝到單獨的DLL中,DLL命名遵循<ProjectName>.DataEntity。資料庫實體類名遵循:資料庫表名去掉複數尾碼,如“s”、“es”等(資料庫表的名稱必須是名詞複數)。 1.1.2 架構規範 實體模塊中 ...


 

0 綜述

 

1 MVP各模塊規範

 

1.1 實體模塊規範

1.1.1 命名規範

    實體類封裝到單獨的DLL中,DLL命名遵循<ProjectName>.DataEntity。資料庫實體類名遵循:資料庫表名去掉複數尾碼,如“s”、“es”等(資料庫表的名稱必須是名詞複數)。

1.1.2 架構規範

    實體模塊中必須包含一個泛型實體介面,供所有數據實體類實現該介面,該介面所繼承介面亦為各實體類所統一實現(例如該介面實現自IEquatable<T>),該介面泛型參數必須為本介面類型,該介面可以不聲明任何成員。例如:

1 namespace TestProj.DataEntity
2 {
3     public interface ITestProjEntity<T> : IEquatable<T>
4         where T : ITestProjEntity<T>
5     {
6     }
7 }

    該介面用於規範實體類編寫。

    該介面命名規範遵循:I+<項目名>+Entity形式,該介面必須為泛型介面,該介面泛型參數必須是本介面。實體類只映射資料庫實際結構,實體類之間主外鍵關聯用程式邏輯維護,即:不採用實體間依賴的方式表示主外鍵關聯(實體類不包含其他實體類的實例對象、列表、集合等)。

    實體類示例代碼如下:

public class Patient : IOpenTCMEntity<Patient>
{
    public string ID { get; set; }   //主鍵ID
    public string Name { get; set; } //姓名

    public bool Equals(Patient other)
    {
        if (other == null)
        {
            return false;
        }
        if (other == this)
        {
            return true;
        }
        bool res =
            other.ID == ID &&
            other.Name == Name;
        return res;
    }
}

 

1.2 資料庫訪問介面

1.2.1 命名規範

    資料庫訪問介面必須封裝到單獨的DLL中,DLL命名遵循 I + <ProjectName>.DataOperate。資料庫訪問類命名遵循:I + <相對應實體類命名> + “DAO”。

1.2.2 架構規範

    資料庫訪問介面必須包含一個泛型介面,該泛型介面用於統一聲明所有公共的資料庫ACID函數,該介面泛型參數必須是資料庫實體類所共同實現的介面類型,該介面命名必須為IBaseDAO。示例代碼如下:

 1 public interface IBaseDAO<E>
 2     where E : IOpenTCMEntity<E>
 3 {
 4     /// <summary>
 5     /// 是否存在ID所對應的記錄
 6     /// </summary>
 7     /// <param name="id"></param>
 8     /// <returns></returns>
 9     bool Exists(string id);
10     /// <summary>
11     /// 是否存在參數對象所描述的記錄(屬性為空表示該屬性不作為查詢條件)
12     /// </summary>
13     /// <param name="condition"></param>
14     /// <returns></returns>
15     bool Exists(E condition);
16     /// <summary>
17     /// 將參數描述的實體對象添加到資料庫中
18     /// </summary>
19     /// <param name="po"></param>
20     /// <returns></returns>
21     bool AddEntity(E po);
22     /// <summary>
23     /// 將參數描述的實體對象集合添加到資料庫中
24     /// </summary>
25     /// <param name="pos"></param>
26     /// <returns></returns>
27     bool AddEntity(List<E> pos);
28     /// <summary>
29     /// 根據ID從資料庫中刪除實體
30     /// </summary>
31     /// <param name="id"></param>
32     /// <returns></returns>
33     bool DelEntity(string id);
34     /// <summary>
35     /// 依據參數描述的資料庫記錄更新資料庫,
36     /// 本操作需要先從資料庫獲取具體的對象。
37     /// </summary>
38     /// <param name="po"></param>
39     /// <returns></returns>
40     bool UpdateEntity(E po);
41     /// <summary>
42     /// 依據參數描述的對象為條件,獲取記錄數。
43     /// </summary>
44     /// <param name="condition"></param>
45     /// <returns></returns>
46     long GetCount(E condition);
47     /// <summary>
48     /// 獲取總記錄數
49     /// </summary>
50     /// <returns></returns>
51     long GetCount();
52     /// <summary>
53     /// 獲取所有實體對象集合
54     /// </summary>
55     /// <returns></returns>
56     List<E> SelectEntity();
57     /// <summary>
58     /// 獲取分頁對象集合
59     /// </summary>
60     /// <param name="beg"></param>
61     /// <param name="len"></param>
62     /// <returns></returns>
63     List<E> SelectEntity(int beg, int len);
64     /// <summary>
65     /// 根據ID獲取一個實體對象
66     /// </summary>
67     /// <param name="id"></param>
68     /// <returns></returns>
69     E SelectEntity(string id);
70     /// <summary>
71     /// 依據條件獲取實體集合
72     /// </summary>
73     /// <param name="condition"></param>
74     /// <returns></returns>
75     List<E> SelectEntity(E condition);
76 }

     針對每個資料庫表創建對應的數據訪問介面,該介面繼承自IBaseDAO,泛型參數為該數據表對應的實體類。代碼示例如下:

1 public interface ITestDAO:IBaseDAO<Test>
2 {
3 }

1.3 數據業務介面規範

1.3.1 命名規範

    業務介面必須封裝到單獨的DLL中,DLL命名遵循<ProjectName>.DataBiz。業務類命名遵循:相對應實體類+"BO"。

1.3.2 架構規範

    資料庫業務介面必須包含一個公用的泛型介面,該泛型介面用於統一聲明所有公共的資料庫ACID函數,該介面泛型參數必須是資料庫實體類所共同實現的介面類型,和一個用於訪問資料庫的IBaseDAO類型屬性。示例代碼如下:

 1 public interface IBaseBO<E, DAO>
 2     where E : IOpenTCMEntity<E>
 3     where DAO : IBaseDAO<E>
 4 {
 5     /// <summary>
 6     /// 資料庫操作對象
 7     /// </summary>
 8     DAO DbOperator { get; set; }
 9     /// <summary>
10     /// 是否存在ID所對飲的記錄
11     /// </summary>
12     /// <param name="id"></param>
13     /// <returns></returns>
14     bool Exists(string id);
15     /// <summary>
16     /// 是否存在參數對象所描述的記錄(屬性為空表示該屬性不作為查詢條件)
17     /// </summary>
18     /// <param name="condition"></param>
19     /// <returns></returns>
20     bool Exists(E condition);
21     /// <summary>
22     /// 將參數描述的實體對象添加到資料庫中
23     /// </summary>
24     /// <param name="po"></param>
25     /// <returns></returns>
26     bool AddEntity(E po);
27     /// <summary>
28     /// 將參數描述的實體對象集合添加到資料庫中
29     /// </summary>
30     /// <param name="pos"></param>
31     /// <returns></returns>
32     bool AddEntity(List<E> pos);
33     /// <summary>
34     /// 根據ID從資料庫中刪除實體
35     /// </summary>
36     /// <param name="id"></param>
37     /// <returns></returns>
38     bool DelEntity(string id);
39     /// <summary>
40     /// 依據參數描述的資料庫記錄更新資料庫,
41     /// 本操作需要先從資料庫獲取具體的對象。
42     /// </summary>
43     /// <param name="po"></param>
44     /// <returns></returns>
45     bool UpdateEntity(E po);
46     /// <summary>
47     /// 依據參數描述的對象為條件,獲取記錄數。
48     /// </summary>
49     /// <param name="condition"></param>
50     /// <returns></returns>
51     long GetCount(E condition);
52     /// <summary>
53     /// 獲取總記錄數
54     /// </summary>
55     /// <returns></returns>
56     long GetCount();
57     /// <summary>
58     /// 獲取所有實體對象集合
59     /// </summary>
60     /// <returns></returns>
61     List<E> SelectEntity();
62     /// <summary>
63     /// 獲取分頁對象集合
64     /// </summary>
65     /// <param name="beg"></param>
66     /// <param name="len"></param>
67     /// <returns></returns>
68     List<E> SelectEntity(int beg, int len);
69     /// <summary>
70     /// 根據ID獲取一個實體對象
71     /// </summary>
72     /// <param name="id"></param>
73     /// <returns></returns>
74     E SelectEntity(string id);
75     /// <summary>
76     /// 依據條件獲取實體集合
77     /// </summary>
78     /// <param name="condition"></param>
79     /// <returns></returns>
80     List<E> SelectEntity(E condition);
81 }

    針對每個資料庫表創建對應的數據訪問介面,該介面繼承自IBaseDAO,泛型參數為該數據表對應的實體類。代碼示例如下:

public interface ISymptomBO : IBaseBO<Pathology, ISymptomDAO>
{
    //TODO:Type your specific business logical code
}

    該介面中可以聲明特定與該數據表的特定業務函數、屬性。

1.4 數據訪問模塊

1.4.1 命名規範

    數據訪問模塊必須封裝為單獨的DLL,DLL文件命名規範遵循<項目名>.DataOperate,數據訪問類遵循 <表名單數形式> + DAO 的命名規範。

1.4.2 架構規範

    數據訪問模塊需要引用System.ComponentModel.Composition命名空間。數據訪問模塊若使用EF6,則必須包含一個數據上下文類,該類命名個規範為<Project>Context,該類用於提供EntityFramework6的數據上下文。    

 數據上下文類結構如下:

public class OpenTCMContext : DbContext
{
    public OpenTCMContext()
        : base("TestConnStr")
    {
    }
    public DbSet<TestTableA> TestTableAContext { get; set; }
    public DbSet<TestTableA> TestTableBContext { get; set; }
}

    數據訪問類之間不互相依賴,每個數據訪問類實現自按資料庫表對應的數據訪問介面,並具備一個私有隻讀的數據上下文對象。數據訪問類每個實現自IBaseDAO的函數不互相引用。

    數據訪問類若使用EF6的形式,就需要辯證的看待資料庫增刪改查的方式,某些簡單的資料庫操作若使用純EF6方式,資料庫交互數量級有按指數翻倍的可能。本文建議的資料庫訪問方式,儘量採用SQL,不涉及大量重覆操作資料庫的情況下,兼顧EF6的便捷操作。數據訪問類需要向MEF容器導出其自身,鑒於每個數據訪問介面皆對應一個單獨的實現類,這裡採用[Export(typeof(<父介面>))]的方式。

  數據訪問類部分代碼示意如下:

[Export(typeof(ITestDAO))]
public class TestDAO : ITestDAO
{
    public TestDAO()
    {
        context = new OpenTCMContext();
    }
    private readonly TestProjContext context;
    public bool Exists(string id)
    {
        var res = context.TestContext.SqlQuery("ID='{0}'", id);
        if (res.FirstOrDefault() == null)
        {
            return false;
        }
        int count = res.Count();
        return count > 0;
    }
        //...
}

1.5 資料庫業務模塊

1.5.1 命名規範

    資料庫業務模塊必須封裝為單獨的DLL,DLL文件命名規範為<項目名>.DataBiz,資料庫業務類命名遵循<對應實體類名> + BO。

1.5.2 架構規範

    資料庫業務類實現自其對應的業務介面,其必須實現介面規定的資料庫操作抽象介面對象屬性,並標註從MEF容器註入該對象實例。併在構造函數中顯式構建該介面對象。該類也需要向MEF容器導出其自身,供頂級業務構建其示例。資料庫業務類參考代碼示例如下:

[Export("TestBO", typeof(ITestBO))]
public class TestBO : ITestBO
{
    public TestBO()
    {
        var catalog = new DirectoryCatalog("./");
        var container = new CompositionContainer(catalog);
        container.ComposeParts(this);
    }
    [Import]
    public ITestDAO DbOperator { get; set; }

    public bool Exists(string id)
    {
        return DbOperator.Exists(id);
    }
        //...
}

2 總結

 至此,一個基於.Net + MEF + EF6 的輕量級系統基礎架構就完成了。其中業務介面依賴於數據操作介面,業務模塊與數據操作模塊分別依賴於其所對應介面,具體模塊之間沒有依賴關係。各介面、具體模塊均需添加實體模塊的引用。

 


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

-Advertisement-
Play Games
更多相關文章
  • 題意 "題目鏈接" Sol 神仙題Orz 尾碼自動機 + 線段樹合併。。。 首先可以轉化一下模型(想不到qwq):問題可以轉化為統計$B$中每個首碼在$A$中出現的次數。(畫一畫就出來了) 然後直接對$A$串建SAM,線段樹合併維護一下siz就行了 cpp include using namespa ...
  • python多線程與多進程 多線程: 案例:掃描給定網路中存活的主機(通過ping來測試,有響應則說明主機存活) 普通版本: 運行效果如下: 在python裡面,線程的創建有兩種方式,其一使用Thread類創建導入Python標準庫中的Thread模塊 from threading import T ...
  • 也許你已經覺得自己可以熟練使用python並能勝任許多開發任務,所以這篇文章是在浪費你的時間。不過彆著急,我們先從一個例子開始: 猜猜看輸出是什麼?你會說不就是0,1,1麽,真的是這樣嗎? 這是為什麼?如果你還不清楚產生錯誤的原因,那就請繼續往下閱讀吧! 本文索引 LEGB原則 名字隱藏和暫時性死區 ...
  • [toc] 函數定義 函數定義與變數定義相似, 函數示例 小結 函數用關鍵字 func 定義。 定義函數時, 函數名在前,返回類型在後 。 一個函數可以有 多個返回值 。 返回值可以指定一個名字(僅用於非常簡單的函數 )。 函數可以 作為參數 。 Go語言中函數 沒有預設參數、可選參數,函數重載 ...
  • 某些類的邏輯非常複雜,簡化代碼幫助理解下邏輯 ...
  • docker在windows下發力的時候必將取代各種虛擬機,並改變程式員的開發習慣,或許還會改變infra的工作。 概要: 在Windows下搭建開發環境一直是infra(我)頭疼的事情。為瞭解決這個問題,跟老闆,程式員商量得出的解決辦法有以下幾種:1.Mac下開發。優點是搭建環境方便,缺點是需要熟 ...
  • [toc] 條件語句 條件語句用 if 關鍵字來判定條件,如: for省略初始條件(及遞增條件), 相當於while語句 初始條件、結束條件、遞增表達式都省略是是一個死迴圈 Go中沒有while語句 ...
  • 現在好些網站都支持掃碼登錄,感覺上安全了很多,但是本地程式掃碼登錄的不多,就用C 實現了一下,需要作如下準備 1. 在官網上申請一個企業微信,有條件的話做個企業認證吧,我們的是認證過的,所以賬號和本地其他系統的賬號是統一的. 2. 在應用中創建一個應用,這個是關鍵,我們掃碼就是和它有關. 3. 點擊 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...