22
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

Pleasanterのテーブル構造やAPI仕様を意識することなく、統一的なインターフェースでデータを操作できるNuGetパッケージ「PleasanterBridge」を作成いたしました。

パッケージ概要

PleasanterBridge は、Pleasanterのデータベースおよび REST APIを簡潔に扱うための .NET ライブラリです。Pleasanter 独自の仕様(複数のテーブル構造、複雑なコンテナ形式)をカプセル化し、ユーザーは統一されたメソッドで操作することができます。

  • 対象フレームワーク: .NET 9
  • C# バージョン: 13.0

作成の経緯

Pleasanterを活用したサービス開発を進める中で、Pleasanter独自のAPI仕様や複数のテーブル構造にアクセスする処理を共通化していきました。これらを整理してまとめなおし、パッケージとして切り出すことで、開発効率と保守性を向上させられると考え、PleasanterBridgeを開発しました。

PleasanterBridgeの特徴

ReferenceTypeの自動判別

Pleasanterでは、同じサイトのデータが Results / Issues / Wikis という3つの異なるテーブルに格納されます。PleasanterBridgeは、これらのテーブル間の差異を内部で吸収し、ユーザーは ReferenceType を意識することなく統一的なインターフェースでアクセス可能になります。

複雑なコンテナ形式が不要

Pleasanterの API では ClassHash: { ClassA: valueA, ... } といった独自のコンテナ構造を作成する必要があります。PleasanterBridge では、すべてのカラムと値を単純な Dictionary の { Key: Value }または、ジェネリック(クラスのインスタンス)形式で渡すだけで、内部で自動的に正しいコンテナに変換されます。

セーフティな入力処理

入力値に誤りがあった場合も安全に処理されます。

  • カラム名を誤ってしまった場合、そのキーは自動的に無視されます
  • 異なる ReferenceType のカラムを誤って渡した場合も、マッチしないものは無視され、エラーにはなりません
  • 事前に検証されたカラム名のみが処理対象となり、予期しない動作を防ぎます

柔軟な導入方法

settingの登録
サーバ接続設定などのsetting受け渡しに推奨される使用方法は、ASP.NET Core のDI(依存性注入コンテナ)への登録となっております。
しかし、DI を使わない環境では、IPleasanterSettings インターフェース経由でインスタンス化したり、機能のインスタンス化の際に直接設定値を渡すことも可能です。

複数のデータベースに対応
PleasanterBridge は、Pleasanter が対応する以下のすべてのデータベースをサポートしており、ユーザーはデータベース間の差異を意識する必要はありません。

  • SQL Server (デフォルト)
  • MySQL
  • PostgreSQL

柔軟なデータ受け渡し方式

データの受け渡し方を、利用シーンに応じて選択できます。

  • Dictionary 方式: 簡易的に Dictionary で値を渡す
  • ジェネリック方式: 正確にカラム名を固定したクラスのインスタンスを渡す

どちらの方式も内部的には同じ処理パスを通るため、シームレスに選択・切り替えが可能です。

機能別の実装概要

API 操作 (PleasanterAPIBridge)

Pleasanter の REST API と HTTP 通信を行い、データの新規作成・更新・削除を実行します。

主要メソッド

  • Insert(): 単一レコードの新規作成
  • BulkInsert(): 複数レコードの一括新規作成
  • Update(): レコード ID による更新、または条件指定による複数レコード更新
  • Upsert() / BulkUpsert(): マッチカラムを指定した更新挿入
  • Delete(): レコード ID による削除、または条件指定による複数レコード削除

内部処理

  • リクエストをPleasanterAPIの仕様に合わせて変換
  • ClassHash・NumHash・DateHash・DescriptionHash・CheckHash といった複数のコンテナを自動生成
  • レスポンスの統一的なハンドリング

Interface

// Dictionary版メソッド
public Task<PleasanterApiResponse> Insert(string siteId, Dictionary<string, object> dataRecord);
public Task<PleasanterApiResponse> BulkInsert(string siteId, List<Dictionary<string, object>> dataRecords);
public Task<PleasanterApiResponse> Update(string referenceId, Dictionary<string, object> updateData);
public Task<List<PleasanterApiResponse>> Update(string siteId, Dictionary<string, object> targetColumns, Dictionary<string, object> updateData);
public Task<List<PleasanterApiResponse>> BulkUpdate(Dictionary<string, object> updateData/*, string keyColumn = "ResultId"*/);
public Task<PleasanterApiResponse> Upsert(string siteId, List<string> matchColumns, Dictionary<string, object> dataRecord);
public Task<PleasanterApiResponse> BulkUpsert(string siteId, List<string> matchColumns, List<Dictionary<string, object>> dataRecords);
public Task<PleasanterApiResponse> Delete(string referenceId);
public Task<List<PleasanterApiResponse>> Delete(string siteId, Dictionary<string, object> targetColumns);

// ジェネリック版メソッド
public Task<PleasanterApiResponse> Insert<T>(string siteId, T dataRecord) where T : class;
public Task<PleasanterApiResponse> BulkInsert<T>(string siteId, List<T> dataRecords) where T : class;
public Task<PleasanterApiResponse> Update<T>(string referenceId, T updateData) where T : class;
public Task<List<PleasanterApiResponse>> Update<TTarget, TUpdate>(string siteId, TTarget targetColumns, TUpdate updateData)
    where TTarget : class
    where TUpdate : class;
public Task<PleasanterApiResponse> Upsert<T>(string siteId, List<string> matchColumns, T dataRecord) where T : class;
public Task<PleasanterApiResponse> BulkUpsert<T>(string siteId, List<string> matchColumns, List<T> dataRecords) where T : class;
public Task<List<PleasanterApiResponse>> Delete<T>(string siteId, T targetColumns) where T : class;

データベース取得 (IPleasanterRepository)

Pleasanter のデータベースに直接接続し、SQL を実行してデータを取得します。

主要機能

  • Select(): 条件指定でレコードを検索

  • ReferenceType の自動判別に基づく正しいテーブルへの SQL 実行

  • 利点

    • REST API では取得できない複雑なクエリも実行可能
    • 直接データベースアクセスのため、API の制限を受けない
    • Pleasanterを経由しないので高速な動作が可能
  • 欠点:

    • Pleasanterを経由しないため、アクセスログが残らない
    • テーブルへのアクセス設定を渡す必要がある(PleasanterBridge全体の制約となります)

Interface

public List<Dictionary<string, object>> Select(string id);
public List<Dictionary<string, object>> Select(string siteId, Dictionary<string, object>? keyValue)

設定ファイル(IPleasanterSettings)

Interface

string ApiyKey { get; set; }
string Url { get; set; }
string Server { get; set; }
string Database { get; set; }
string UserId { get; set; }
string Password { get; set; }
DatabaseType DatabaseType { get; set; }

実装例

// Dictionary 方式での新規作成
var targetSiteId = "100";
var data = new Dictionary<string, object>
{
    { "Title", "新規タスク" },
    { "Body", "タスクの説明" },
    { "Class_A", "分類A" }
};
var result = await bridge.Insert(targetSiteId, data);

var targetReferenceId = "101";

// ジェネリック方式での更新
var updateData = new TaskUpdateRequest 
{ 
    Title = "更新後のタスク",
    ClassA = "分類A Updated" 
};
await bridge.Update<TaskUpdateRequest>(targetReferenceId, updateData);

おわりに

現在実装済みの機能については、正しく稼働することを確認しています。
今後のアップデート予定は以下の通りです。

  • 画像ファイルの操作対応(作業中)
  • エラー処理およびログ出力の充実
  • 詳細な使用方法のドキュメント化と README への記載
  • NuGet への公開

これらの準備が完了次第、パッケージの公開をいたします。ぜひご利用ください。

22
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?