はじめに
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 への公開
これらの準備が完了次第、パッケージの公開をいたします。ぜひご利用ください。