ABP架構用Dapper實現通過SQL訪問資料庫

來源:互聯網
上載者:User

標籤:mys   web   分享圖片   mysql   sha   執行   word   配置   程式   

為了防止不提供原網址的轉載,特在這裡加上原文連結:
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容器,直接進行註冊和解析操作。

// 以單例模式註冊類型TIocManager.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

ABP架構用Dapper實現通過SQL訪問資料庫

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.