手工搭建基於ABP的框架(2) - 訪問資料庫

来源:http://www.cnblogs.com/skabyy/archive/2017/11/13/7517397.html
-Advertisement-
Play Games

在ABP框架下使用NHibernate和Dapper實現資料庫訪問。 ...


為了防止不提供原網址的轉載,特在這裡加上原文鏈接:
http://www.cnblogs.com/skabyy/p/7517397.html

本篇我們實現資料庫的訪問。我們將實現兩種資料庫訪問方法來訪問一個SQLite資料庫——使用NHibernate實現的ORM映射訪問和使用Dapper實現的SQL語句訪問。然後完成前一篇未完成的CreateTweetGetTweets介面。

在開始之前,先做一些準備工作,新建Domain層的Module:

public class MyTweetDomainModule : AbpModule
{
    public override void Initialize()
    {
        IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
    }
}

同時MyTweetApplicationModule添加對MyTweetDomainModule的依賴:

[DependsOn(typeof(MyTweetDomainModule))]
public class MyTweetApplicationModule : AbpModule

安裝NuGet包Abp.NHibernateMyTweet.DomainMyTweet.Infrastructure

下麵我們將完成這些步驟來實現資料庫的訪問:

  1. 配置資料庫連接
  2. 新建tweet表以及相應的Model類型
  3. 實現訪問數據的Repository
  4. Dapper實現通過SQL訪問資料庫

使用Fluent NHibernate配置資料庫連接

我們這裡使用的資料庫是SQLite資料庫,其他資料庫的配置也是類似的。我們將連接到App_Data文件夾下的一個SQLite資料庫。新建LocalDbSessionProvider類併在構造函數處配置資料庫連接。由於LocalDbSessionProvider實現了介面ISingletonDependency,模塊初始化時LocalDbSessionProvider會以單例的形式註冊到IoC容器。

public class LocalDbSessionProvider : ISessionProvider, ISingletonDependency, IDisposable
{
    protected FluentConfiguration FluentConfiguration { get; private set; }
    private ISessionFactory _sessionFactory;

    public LocalDbSessionProvider()
    {
        FluentConfiguration = Fluently.Configure();
        // 資料庫連接串
        var connString = "data source=|DataDirectory|MySQLite.db;";
        FluentConfiguration
            // 配置連接串
            .Database(SQLiteConfiguration.Standard.ConnectionString(connString))
            // 配置ORM
            .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()));
        // 生成session factory
        _sessionFactory = FluentConfiguration.BuildSessionFactory();
    }
    
    
    private ISession _session;
    public ISession Session
    {
        get
        {
            if (_session != null)
            {
                // 每次訪問都flush上一個session。這裡有效率和多線程問題,暫且這樣用,後面會改。
                _session.Flush();
                _session.Dispose();
            }
            _session = _sessionFactory.OpenSession();
            return _session;
        }
    }

    public void Dispose()
    {
        _sessionFactory.Dispose();
    }
}

這裡每次用到session都只是簡單地把上一次的session flush了,然後打開新的session。這會有效率和多線程衝突的問題。這裡只是單純為了展示實現資料庫鏈接的方法而先用的簡單實現。後面做工作單元(UoW)時會解決這個問題。

為了NHibernate能創建SQLite的連接,還需要安裝System.Data.SQLite.CoreMyTweet.Web(其他資料庫的話要安裝其他相應的包)。

新建tweet表以及相應的Model類型

我們用tweet表保存tweet數據。tweet數據表介面以及對應Model屬性如下:

資料庫欄位 Model屬性 類型 描述
pk_id PkId string 主鍵
content Content string 內容
create_time CreateTime string 創建時間

使用SQLite工具新建MySQLite.db文件,並新建表tweet
然後將MySQLite.db文件拷貝到App_Data文件夾下。

CREATE TABLE `tweet` (
    `pk_id` TEXT,
    `content`   TEXT,
    `create_time`   TEXT NOT NULL,
    PRIMARY KEY(`pk_id`)
);

接下來新建Model類Tweet以及映射TweetMapperTweet繼承Entity<string>,其中的string表示Tweet的主鍵Idstring類型的。TweetMapper繼承ClassMap<Tweet>,上面LocalDbSessionProvider構造函數執行到.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))這個方法時,會用反射的方式搜索程式集中ClassMap<T>的子類,建立Model和資料庫表的映射(Tweettweet表的映射)。

public class Tweet : Entity<string>  // 主鍵為string類型
{
    public string Content { get; set; }
    public DateTime CreateTime { get; set; }
}

public class TweetMapper : ClassMap<Tweet>
{
    public TweetMapper()
    {
        // 禁用惰性載入
        Not.LazyLoad();
        // 映射到表tweet
        Table("tweet");
        // 主鍵映射
        Id(x => x.Id).Column("pk_id");
        // 欄位映射
        Map(x => x.Content).Column("content");
        Map(x => x.CreateTime).Column("create_time");
    }
}

實現Repository與增查介面

Repository即是DDD中的倉儲,它封裝了數據對象的增刪改查操作。ABP的NhRepositoryBase已經實現了常用的增刪改查功能,因此這裡只需要繼承一下就行了。

public interface ITweetRepository : IRepository<Tweet, string> { }

public class TweetRepository : NhRepositoryBase<Tweet, string>, ITweetRepository
{
    public TweetRepository()
        : base(IocManager.Instance.Resolve<LocalDbSessionProvider>())
    { }
}

最後,修改MyTweetAppService,實現CreateTweet介面和GetTweets介面。

public class CreateTweetInput
{
    public string Content { get; set; }
}

public class MyTweetAppService : ApplicationService, IMyTweetAppService
{
    public ITweetRepository TweetRepository { get; set; }

    public object GetTweets(string msg)
    {
        return TweetRepository.GetAll().OrderByDescending(x => x.CreateTime).ToList();
    }

    public object CreateTweet(CreateTweetInput input)
    {
        var tweet = new Tweet
        {
            Id = Guid.NewGuid().ToString("N"),
            Content = input.Content,
            CreateTime = DateTime.Now
        };
        var o = TweetRepository.Insert(tweet);
        return o;
    }
}

大功告成!測試一下。用Postman調用CreateTweet介面插入一條tweet:

然後調用GetTweets查詢:

ABP的依賴註入

可能有同學會疑惑,在MyTweetAppService中只聲明瞭ITweetRepository類型的屬性TweetRepository,但是並沒有進行賦值,那麼這個屬性的對象實例是哪裡來的呢?這就涉及到ABP框架的依賴註入策略了。

ABP基於Castle Windsor框架實現自己的依賴註入功能。依賴註入最基本的功能無非是註冊(Register)和解析(Resolve)兩個,註冊功能將對象註冊到IoC容器,解析功能根據類名或介面名獲從IoC容器獲取已註冊的對象。我們可以直接通過IocManager獲得Castle Windsor的IoC容器,直接進行註冊和解析操作。

// 以單例模式註冊類型T
IocManager.Register<T>(Abp.Dependency.DependencyLifeStyle.Singleton);
// 以臨時對象模式註冊類型T,解析的時候會生成T的一個新對象
IocManager.Register<T>(Abp.Dependency.DependencyLifeStyle.Transient);
// 從IoC容器解析已註冊的類型T的對象
var obj = IocManager.Resolve<T>();

還有一些其他方法可以做註冊和解析,具體可以參照ABP的文檔。不過一般都不需要使用這些方法。ABP框架有一套依賴註入的規則,通過編寫應用程式時遵循最佳實踐和一些約定,使得依賴註入對於開發者幾乎是透明的。

ABP的註冊

基本上每個模塊的初始化方法都會有這麼一行代碼:

IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());

模塊初始化時,ABP會搜索這個模塊所在的程式集,自動註冊滿足常規註冊條件與實現幫助介面的類。

常規註冊

ABP自動註冊所有Repositories, Domain Services, Application Services, MVC 控制器和Web API控制器。ABP通過判斷是否實現了相應介面來判斷是不是上述幾類。例如下麵的MyAppService

public interface IMyAppService : IApplicationService { }
public class MyAppService : IMyAppService { }

由於它實現了介面IApplicationService,ABP會自動註冊,我們就可以通過IMyAppService解析出一個MyAppService對象。

通過常規註冊的類的生命期都是transient(臨時的),每次解析時都會生成一個新的臨時對象。

幫助介面

ABP另外提供了ITransientDependencyISingletonDependency兩個介面。這兩個介面前面也有用到過了。實現了ITransientDependency的類會被註冊為transient。而實現了ISingletonDependency的類則被註冊為單例。

ABP的解析

除了手工解析外,還可以通過構造函數和公共屬性註入來獲取類的依賴。這也是最常用的方法。例如:

public class MyAppService : IMyAppService
{
    public ILogger Logger { get; set; }
    private IMyRepository _repo;
    public MyAppService(IMyRepository repo)
    {
        _repo = repo;
    }
}

ILogger從公共屬性註入,IMyRepository從構造函數註入。註入過程對開發者是透明的,開發者不需要去寫註入的代碼。

QueryService - 使用SQL語句查詢數據

實際開發中,經常需要直接使用SQL進行數據訪問。查詢邏輯比較複雜時直接使用SQL可以避免複雜的Mapper。通常複雜的Mapper會導致低效率的查詢甚至會觸發NHibernate一些奇怪的bug。實際上,在開發中,對於單純的讀取數據的功能(即使查詢邏輯不複雜),我們建議直接使用SQL查詢實現。直接使用SQL查詢在調試時更為方便——直接拷貝SQL語句到SQL客戶端執行即可檢驗該語句是否正確。

下麵簡要介紹一下使用Dapper來實現資料庫查詢功能。封裝了sql查詢操作的類我們稱為QueryService。

首先,安裝dapper包到MyTweet.Infrastructure。在MyTweet.Infrastructure實現QueryService的基類BaseQueryService

public class BaseQueryService : ITransientDependency
{
    private ISessionProvider _sessionProvider;

    protected BaseQueryService(ISessionProvider sessionProvider)
    {
        _sessionProvider = sessionProvider;
    }

    public IEnumerable<T> Query<T>(string sql, object param = null)
    {
        var conn = _sessionProvider.Session.Connection;
        return conn.Query<T>(sql, param);
    }
}

Dapper給System.Data.IDbConnection介面擴展了Query<T>方法,該方法執行SQL查詢並將查詢結構映射為IEnumerable<T>類型的對象。為了使用這個擴展方法,還需在文件開頭加個using語句。

using Dapper;

QueryService並不在ABP依賴註入的常規註冊規則里,所以讓BaseQueryService實現了ITransientDependency,這樣它的子類都會自動被註冊到IoC容器。

接下來在MyTweet.Domain新建類TweetQueryService,它負責實現具體的SQL查詢。方法SearchTweets實現了查詢包含關鍵詞keyword的所有tweet。

public interface ITweetQueryService
{
    IList<Tweet> SearchTweets(string keyword);
}

public class TweetQueryService : BaseQueryService, ITweetQueryService
{
    public TweetQueryService() : base(IocManager.Instance.Resolve<LocalDbSessionProvider>())
    { }

    public IList<Tweet> SearchTweets(string keyword)
    {
        var sql = @"select
                        pk_id Id,
                        content Content,
                        create_time CreateTime
                    from tweet
                    where content like '%' || @Keyword || '%'";
        return Query<Tweet>(sql, new { Keyword = keyword ?? "" }).ToList();
    }
}

最後在MyTweetAppService實現查詢tweet數據的介面GetTweetsFromQS

public ITweetQueryService TweetQueryService { get; set; }

public object GetTweetsFromQS(string keyword)
{
    return TweetQueryService.SearchTweets(keyword);
}    

測試一下:

結束

本文介紹了通過NHibernate以及Dapper進行資料庫訪問的方法,簡單說明瞭ABP依賴註入策略。現在資料庫連接部分的代碼只是單純為了演示的簡單實現,沒有做合理的資料庫Session管理,會有效率和多線程衝突的問題。後面會加上工作單元(Unit of Work)來解決這些問題。

最後,放上代碼鏈接:https://github.com/sKabYY/MyTweet-AbpDemo


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

-Advertisement-
Play Games
更多相關文章
  • 第1章 Oracle Database 12c Release 2安裝詳解 1.1 下載方法 oracle官網https://www.oracle.com 1)打開官方網站,找到下載連接 2)選擇更多下載。 3)選擇資料庫版本,這裡選擇的是目前的最新版本 4)接收許可協議,選在linux版本進行下載 ...
  • lamp環境已搭建完成基礎之上 上傳owncloud-10.0.3.zip到Linux 解壓owncloud-10.0.3.zip [root@localhost ~]#unzip owncloud-10.0.3.zip 複製解壓後的文件到/var/www/html [root@localhost ...
  • 要想從現在的低薪(年薪10萬以下)快讀變成未來的高新(年薪30萬以上)我們要做的就只有從自身改變開始! 人改變自己的勇氣,朱啊喲取決於我們自己當前的痛苦程度!直到某一天真的迴避不了了,才會被動的改變,被動改變結果往往是來不及的,或者花的代價相當高,獲得的回報又比較低!改變自己越早越好!成功的人一般都 ...
  • 本文需要實現的功能如下:某文件夾下具有由按數字編號命名的文件夾,需要刪除除最大編碼外的文件。 具體實現 大致思路:迴圈遍歷該文件夾下所有文件,正則匹配出最大編碼文件;然後迴圈文件,刪除除最大編碼外的文件。 實現代碼如下: 實現效果:文件夾:/root/cloud/builds 執行腳本後: 用到的S ...
  • Mysql安裝 CentOS 7 版本將MySQL資料庫軟體從預設的程式列表中移除,用mariadb代替了。MariaDB資料庫管理系統是MySQL的一個分支,主要由開源社區在維護,採用GPL授權許可。開發這個分支的原因之一是:甲骨文公司收購了MySQL後,有將MySQL閉源的潛在風險,因此社區採用 ...
  • Memcached 是一個高性能的分散式記憶體對象緩存系統,用於動態Web應用以減輕資料庫負載。它通過在記憶體中緩存數據和對象來減少讀取資料庫的次數,從而提高動態、資料庫驅動網站的速度。Memcached基於一個存儲鍵/值對的hashmap。其守護進程(daemon )是用寫的,但是客戶端可以用任何語言 ...
  • ABP是“ASP.NET Boilerplate Project (ASP.NET樣板項目)”的簡稱。ASP.NET Boilerplate是一個用最佳實踐和流行技術開發現代WEB應用程式的新起點,它旨在成為一個通用的WEB應用程式框架和項目模板。框架ABP是基於最新的ASP.NET CORE,AS ...
  • 一、系統介紹 本軟體主要讓你的文件夾多彩多樣化,而不是千篇一律黃色的文件夾,相信豐富多彩的顏色更便於記憶、能讓心情愉快些。 文件夾顏色眾多,到底有多少種呢,10種? 100種? 1000種? NO,精確計算是255*255*255 , 只是很多顏色很相近, 而能夠明顯有差別的不是很多,為了便於自己記 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...