ファイルマネージャの作成3「コメントをSQLiteに記録」

ブログ コンピュータ
ブログ

ファイルやフォルダに紐づくコメントを入力し記録する機能を実装しました。

保存する先はSQLiteでテーブルを作成しました。

以下のコードはテーブルの項目の定義になります。
ファイル名:CommentTable.cs

namespace FileManager01.Domain.Entities;

public class CommentTable
{
    public string FullPath { get; set; } = "";
    public string Comment { get; set; } = "";
}

EntityFrameworkでデータベースにアクセスするためのDbContextクラスは以下のコードになります。
データベース、テーブルの作成とレコードの挿入と更新する機能を持たせています。
ファイル名:AppDbContext.cs

using FileManager01.Domain.Entities;
using FileManager01.Domain.Repositories;

using Microsoft.EntityFrameworkCore;

namespace FileManager01.Infrastructure;

public class AppDbContext : DbContext
{
    public DbSet<CommentTable> CommentTable => Set<CommentTable>();
    public string DbPath { get; set; }

    // コンストラクタ
    public AppDbContext(string dbPath = "./app.db")
    {
        DbPath = dbPath;
        this.Database.EnsureCreated();
    }     

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
        optionsBuilder.UseSqlite($"Data Source={DbPath}");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<CommentTable>(entity =>
        {
            // エンティティクラス(LastChange)とテーブルLastChangeを紐づける
            entity.ToTable("Comment");

            // 主キーの定義... (複合の場合 e => new {e.A, e.B} )
            entity.HasKey(e => e.FullPath); 

            // プロパティDateにNOT NULL属性を付与
            entity.Property(e => e.Comment)
                  .IsRequired();
        });
    }

    // 追加または更新
    public async Task SaveOrUpdateEntityAsync(CommentTable entity)
    {
        var existingEntity = await this.CommentTable.FindAsync(entity.FullPath);
        if (existingEntity is null)
        {
            this.CommentTable.Add(entity);
        }
        else
        {
            this.Entry(existingEntity).CurrentValues.SetValues(entity);
        }
        await this.SaveChangesAsync();
    }

}

以下のコードはカレントディレクトリのファイルやサブディレクトリを取得していますが、データベースからコメントを取得するようにしてみました。

ファイル名:FileLisService.cs

using FileManager01.Domain.Entities;
using FileManager01.Domain.Repositories;

namespace FileManager01.Infrastructure;

public class FileLisService : IFileLisRepositorty
{
    public async Task<IFileListEntity> GetEntityAsync(string path)
    {

        var fileSystemUtility = new FileSystemUtility(path);

        int pathType = (int)FileSystemType.Directory;

        string name = fileSystemUtility.GetName();

        var result = new FileListEntity(path, pathType, name);

        foreach(string fullPath in fileSystemUtility.GetEntity())
        {
            var n = Path.GetFileName(fullPath);
            var pt = Directory.Exists(fullPath) ? (int)FileSystemType.Directory : (int)FileSystemType.File;
            var obj = new FileListEntity(fullPath, pt, n);

            // データベースからコメント取得
            using (var context = new AppDbContext())
            {
                var entity = await context.CommentTable.FindAsync(fullPath);
                if (entity is not null)
                {
                    obj.Comment = entity.Comment;
                }
            }
            

            result.SubEntites.Add(obj);
        }

        return result;
    }
}

アプリケーションからの呼び出しのコードは以下のようになります。

ファイル名:MainWindowViewModel_ListView.cs

   // リストビューを更新
    async Task Update_ListView(string path = ".")
    {
        var tcs = new TaskCompletionSource<bool>();
        using var v = ListView_Entities.ObserveResetChanged<int>().Subscribe(x=>
        {
        // collectionのクリアが完了すると呼ばれるイベント。
            tcs.SetResult(true);    // 結果にtureをセット
        });
        ListView_Entities.ClearOnScheduler();
        await tcs.Task;  // tcsの終了を待つ

        // クリア後の処理をこちらに書く
        //var obj = Factories.GetFileSystemEntitiy(path);
        var entity = await fileListRepository.GetEntityAsync(path);

        foreach(var sub in entity.SubEntites)
        {
            var item = new FileListItem(sub);
            item.Comment.Skip(1).Subscribe(async comment =>
            {
                string fullPath = ListView_SelectedItem.Value.FullPath;
                //Debug.Print($"File:{fullPath} Comment:{comment}");
                using (var context = new AppDbContext())
                {
                    var entity = new CommentTable()
                    {
                        FullPath = fullPath,
                        Comment = comment,
                    };
                    await context.SaveOrUpdateEntityAsync(entity);
                }
            });

            ListView_Entities.AddOnScheduler(item);
        }
    }

コメントの表示及び入力用のテキストボックスとバインドしたViewModelをSubscribeして、変更をきっかけにデータベースを更新しています。

データベースへのアクセスは非同期処理にしてみましたが、アプリ起動からリストビューが初期表示まで待ちが発生する用になりました。
一度表示してしまえば、ディレクトリの移動では待ちは発生しないので、これ以上遅くならなければ、このままにしたいと思います。

・20250608プレビューとログ表示をタブで切り替え

・20250608おきにいりディレクトリの記録機能追加

コメント