FreeSql 如何實現 Sqlite 跨庫查詢

FreeSql 是 .NetFramework 4.6+、.NetCore 下的 ORM 功能庫,提供了豐富的功能,支持五種流行數據庫 MySql/SqlServer/PostgreSQL/Oracle/Sqlite。mysql

正常的數據庫都支持跨庫,然而 Sqlite 默認不支持,或者說支持起來較爲麻煩,FreeSql 最關心的是通用、易用性,本文介紹 FreeSql 如何實現 Sqlite 跨庫操做。git

故事發生在 CodeFirst 自由開發

FreeSql 支持並推薦使用 CodeFirst 方式開發項目,這種開發方式很是自由,如同 FreeSql 的命名通常。github

以下定義兩個實體(文章、評論):sql

class Topic {
    public Guid Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime CreateTime { get; set; }
}
[Table(Name = "xxxtb.Comment")]
class Comment {
    public Guid Id { get; set; }
    public Guid TopicId { get; set; }
    public Topic Topic { get; set; }
    public string Nickname { get; set; }
    public string Content { get; set; }
    public DateTime CreateTime { get; set; }
}

咱們但願將 Topic 的數據存到主庫,Comment 的數據存到別外一個庫(xxxtb)。好比使用 mysql,不指定數據庫狀況下,將操做當前數據庫下的表。數據庫

其餘 ado.net 或 ORM 將面臨的問題(默認狀況下):異步

一、驅動只打開了一個庫,或者須要手工調用驅動的方法對其餘庫進行附加;測試

二、項目中可能須要定義多個 orm,實現對多個數據庫的存儲和查詢;優化

三、沒法使用跨庫聯表查詢;ui

解決用戶使用問題

使用習慣是 FreeSql 主要攻克的難題,其餘數據庫都行,【吐槽】就你丫的 Sqlite 奇葩,同鏈接下默認作不到跨庫操做(或者說使用不方便)。this

好在現在的 .NET 庫大多數都已經開源,因而翻閱 System.Data.SQLite.Core 源碼作了總結:

SQLiteConnection 鏈接對象在 Open 後,執行以下命令可附加多個數據庫;

attach database [xxxtb.db] as [xxxtb];

因而,

第一步:實現一個擴展方法,使用 OpenAndAttach 代替 Open:

public static void OpenAndAttach(this DbConnection that, string[] attach) {
    that.Open();

    if (attach?.Any() == true) {
        var sb = new StringBuilder();
        foreach(var att in attach)
            sb.Append($"attach database [{att}] as [{att.Split('.').First()}];\r\n");

        var cmd = that.CreateCommand();
        cmd.CommandText = sb.ToString();
        cmd.ExecuteNonQuery();
    }
}
//異步方法的實現省略...

第二步:增長 ConnectionString 參數 Attachs

Data Source=|DataDirectory|\document.db;Attachs=xxxtb.db;Pooling=true;Max Pool Size=10

第三步:SqliteConnectionPool 實施

一、解析 Attachs;

var att = Regex.Split(_connectionString, @"Attachs\s*=\s*", RegexOptions.IgnoreCase);
if (att.Length == 2) {
    //此條件說明存在,找到 Attachs 配置的值,而且它支持以逗號分割
    var idx = att[1].IndexOf(';');
    Attaches = (idx == -1 ? att[1] : att[1].Substring(0, idx)).Split(',');
}

二、將原有 Open 方法替換成 OpenAndAttach;

大功告成

編碼與實施過程完成,接下來測試結果,仍然使用上方給出的兩個實體類型。

static IFreeSql sqlite = new FreeSql.FreeSqlBuilder()
    .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Attachs=xxxtb.db;Pooling=true;Max Pool Size=10")
    .UseAutoSyncStructure(true)
    .UseLazyLoading(true)
    .Build();

//秀一波 FreeSql.Repository 擴展包
//安裝方法:dotnet add package FreeSql.Repository
var topicRepository = sqlite.GetGuidRepository<Topic>();
var commentRepository = sqlite.GetGuidRepository<Comment>();

//添加測試文章
Guid topicId = FreeUtil.NewMongodbId();
topicRepository.Insert(new Topic {
    Id = FreeUtil.NewMongodbId(),
    Title = "文章標題1",
    Content = "文章內容1",
    CreateTime = DateTime.Now
});

//添加10條測試評論
var comments = Enumerable.Range(0, 10).Select(a => new Comment {
    Id = FreeUtil.NewMongodbId(),
    TopicId = topicId,
    Nickname = $"暱稱{a}",
    Content = $"評論內容{a}",
    CreateTime = DateTime.Now
});
var affrows = commentRepository.Insert(comments);

var find = commentRepository.Select.Where(a => a.Topic.Title == "文章標題1").ToList();
//SELECT a."Id", a."TopicId", a."Nickname", a."Content", a."CreateTime" 
//FROM "xxxtb"."Comment" a, "Topic" a__Topic 
//WHERE (a__Topic."Title" = '文章標題1')

//find 查詢出了10條數據

而後咱們使用 navicat 附加兩個數據庫查看:

其餘說明

一、FreeUtil.NewMongodbId 是生成有序的 Guid 值,在 FreeSql 中實現,其實可使用 Guid.NewGuid,這裏我認可有秀的嫌疑;

二、文章中的代碼沒有過多的依賴,在 vs2017+.netcore2.2 測試一次運行經過,sqlite 的優點免安裝服務;

三、FreeSql 支持 CodeFirst,即建好實體運行程序,表就會建立;

四、FreeSql.Repository 是擴展包,實現通用 CURD 倉儲層功能,文檔:https://github.com/2881099/FreeSql/wiki/Repository

這個功能其實在 FreeSql 早期就已經實現了,可是一直沒能有時間將過程經驗整理成文章,今天把文章寫完寫全,但願能給你們帶來一點「驚嚇」。FreeSql還有更多細節優化並非路人一眼能看透,若是以爲寫得不錯麻煩點個贊,這也是我繼續寫下去的源動力。

一遍看不明白的話,建議多看幾遍。謝謝觀看!

相關文章
相關標籤/搜索