Avalonia 使用EFCore呼叫SQLite實現Singleton全域性註冊

2023-07-21 06:01:15

Avalonia 使用EFCore呼叫SQLite實現Singleton全域性註冊

本篇部落格是我的開源專案TerraMours.Chat.Ava的更新的記錄分享,本次更新使用EntityFrameWork Core呼叫SQLite,實現資料的在地化和查詢的優化,刪除了dbpross類(直接呼叫SQLite的操作類)。大大提高了程式碼的簡潔度和易讀性。通過全域性註冊的ChatDbcontext物件,是運算元據庫變的非常方便。對專案感興趣的同學可以到github上搜尋TerraMours.Chat.Ava。希望通過該專案瞭解和學習Avalonia開發的朋友可以在我的github上拉取程式碼,同時希望大家多多點點star。

https://github.com/raokun/TerraMours.Chat.Ava

專案的基礎通用功能和業務程式碼開發在之前部落格中介紹過了,想了解的同學跳轉學習:

基於Avalonia 11.0.0+ReactiveUI 的跨平臺專案開發1-通用框架

基於Avalonia 11.0.0+ReactiveUI 的跨平臺專案開發2-功能開發

瞭解Avalonia建立模板專案-基礎可跳轉:

建立Avalonia 模板專案-基礎

本次我主要分享的內容是專案中使用EFCore呼叫SQLite的實現。

1.安裝nuget包

<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0-preview.6.23329.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0-preview.6.23329.4">
    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

2.建立一個繼承自 DbContext 的類

建立ChatDbcontext繼承自 DbContext 的類,並在建構函式中將連線字串傳遞給 DbContextOptions 物件。

程式碼如下:

public class ChatDbcontext :DbContext{
    public DbSet<ChatMessage> ChatMessages { get; set; }
    public DbSet<ChatList> ChatLists { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlite($"Data Source={AppSettings.Instance.DbPath}"); // 這裡是您的 SQLite 連線字串
    protected override void OnModelCreating(ModelBuilder modelBuilder) {
        // 新增實體設定
        modelBuilder.Entity<ChatMessage>().HasKey(e => e.ChatRecordId);
        modelBuilder.Entity<ChatList>().HasKey(e => e.Id);

        base.OnModelCreating(modelBuilder);
    }

    //切換資料庫連線
    public void ChangeConnection(string connectionString) {
        // 修改資料庫連線字串,並重新設定 DbContext
        Database.GetDbConnection().ConnectionString = connectionString;
        ChangeTracker.AutoDetectChangesEnabled = false;
        ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        ChangeTracker.AutoDetectChangesEnabled = true;
    }
    /// <summary>
    /// 檢查表是否存在
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public bool CheckIfTableExists<T>() where T : class {
        var tableExists = this.Model.FindEntityType(typeof(T)) != null;

        return tableExists;
    }

}

其中包括:

  1. OnConfiguring 根據組態檔中的資料庫地址設定資料庫連線
  2. OnModelCreating 中設定實體類的主鍵
  3. ChangeConnection 方法實現切換資料庫連線
  4. CheckIfTableExists 方法 檢查指定的表是否存在

3.DbContext 註冊為全域性服務

1.建立一個靜態欄位

VMLocator類中,建立一個靜態欄位來儲存 DbContext 的範例

程式碼如下:

private static ChatDbcontext _chatDbcontext;
public static ChatDbcontext ChatDbcontext {
    get => (_chatDbcontext ??= new ChatDbcontext());
    set => _chatDbcontext = value;
}

2.建立ChatProcess資料庫操作類

程式碼如下:

 /// <summary>
/// 建立並初始化資料庫
/// </summary>
public void CreateDatabase() {
    using (var context = new ChatDbcontext()) {
        context.Database.Migrate();
        VMLocator.ChatDbcontext = context;
    }
}

/// <summary>
/// 判斷載入的資料庫表是否完整
/// </summary>
public async Task<bool> CheckTableExists(string selectedFilePath) {
    VMLocator.ChatDbcontext.ChangeConnection(selectedFilePath);
    return (VMLocator.ChatDbcontext.CheckIfTableExists<ChatMessage>() && VMLocator.ChatDbcontext.CheckIfTableExists<ChatList>());
}

其中:

  1. CreateDatabase方法的作用是初始化資料庫,如果在指定的資料庫檔案地址中不存在檔案,則在存取資料庫時,SQLite 資料庫引擎會嘗試建立一個新的資料庫檔案。這意味著,如果指定的資料庫檔案地址沒有檔案,EF Core 與 SQLite 的整合會自動建立一個新的資料庫檔案。
  2. CheckTableExists 方法判斷載入的資料庫表是否完整

3.ChatDbcontext初始化和賦值

ChatDbcontext初始化和賦值在MainWindow_Loaded方法中,在首頁載入時,判斷設定中的資料庫檔案地址。並載入資料庫。

4.DbContext的使用

如何在程式中使用DbContext來查詢資料庫是重點,下面是一些應用的場景:

程式碼如下:

//資料載入
            VMLocator.DataGridViewModel.ChatList=VMLocator.ChatDbcontext.ChatLists.ToObservableCollection();
            VMLocator.ChatViewModel.ChatHistory = VMLocator.ChatDbcontext.ChatMessages.ToObservableCollection();

這裡查詢資料庫的記錄賦值給DataGridViewModelChatViewModel,實現資料庫的資料的載入。

簡簡單單的兩行程式碼,完成了對談列表和聊天記錄的資料載入。

ToObservableCollection擴充套件

我們需要把資料庫查詢的資料轉換成ObservableCollection的集合做Binding,我們寫一個EF的擴充套件方法來實現這個轉換。

程式碼如下:

/// <summary>
/// 擴充套件方法
/// </summary>
public static class ObservableCollectionExtensions {
    public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> source) {
        return new ObservableCollection<T>(source);
    }
}

更多的使用方法可以在程式碼中檢視TerraMours.Chat.Ava

5.生成資料遷移檔案

執行Add-Migration 命令

Add-Migration Init0720

由於我們在CreateDatabase程式碼裡實行了資料庫的更新,所以我們在這裡不需要執行Update-Database 命令

值得注意的是,我們在修改過欄位後,一定要執行Add-Migration 命令生成資料遷移檔案,這是資料庫初始化和更新的基礎

6.總結

通過EF core 等ORM框架運算元據庫為我們開發專案時提供了便捷。在不追求極限的速度的前提下,使用EntityFrameWork來做查詢真的很方便。

通過ChatDbcontext來運算元據庫,讓開發變的簡單。希望看完後能給大家帶來幫助。

目前程式還沒有完全開發完成。後續的開發我會及時跟進。閱讀如遇樣式問題,請前往個人部落格瀏覽:https://www.raokun.top

目前web端ChatGPT:https://ai.terramours.site

當前開源專案地址:https://github.com/raokun/TerraMours.Chat.Ava