はじめに
前回までで、家計簿アプリが一旦完成しました。(AIがやりました)
今回はマスタを実装します。
プロンプト
マスタ管理に商品マスタを追加してください。
回答
商品カテゴリマスタ、支払方法マスタがあるなら、
商品マスタ
も追加した方が運用しやすくなります。
1. テーブル追加
現在のDBへ追加
CREATE TABLE Products
(
Id INTEGER PRIMARY KEY AUTOINCREMENT,
ProductName TEXT NOT NULL,
CategoryId INTEGER NOT NULL,
Note TEXT,
FOREIGN KEY(CategoryId)
REFERENCES Categories(Id)
);
2. メニュー追加
MasterManageForm
現在
タブ
├ 商品カテゴリ
└ 支払方法
なら
タブ
├ 商品カテゴリ
├ 支払方法
└ 商品マスタ
追加
3. 画面構成
商品マスタタブ
┌─────────────────────────────┐
│商品名 [ ] │
│カテゴリ [ComboBox▼ ] │
│備考 [ ] │
│ │
│[追加] [更新] [削除] │
│ │
│DataGridView │
│ID 商品名 カテゴリ 備考 │
└─────────────────────────────┘
4. コントロール追加
Designer
private TabPage tabProducts;
private DataGridView dgvProducts;
private TextBox txtProductName;
private ComboBox cboProductCategory;
private TextBox txtProductNote;
private Button btnAddProduct;
private Button btnDeleteProduct;
private Button btnUpdateProduct;
5. カテゴリロード
private void LoadProductCategories()
{
cboProductCategory.Items.Clear();
using SqliteConnection conn =
DbHelper.GetConnection();
conn.Open();
string sql =
@"
SELECT
Id,
CategoryName
FROM Categories
ORDER BY CategoryName
";
using SqliteCommand cmd =
new SqliteCommand(sql, conn);
using SqliteDataReader reader =
cmd.ExecuteReader();
while (reader.Read())
{
cboProductCategory.Items.Add(
new ComboItem(
reader.GetInt32(0),
reader.GetString(1)));
}
}
6. ComboBox用クラス
public class ComboItem
{
public int Id { get; }
public string Name { get; }
public ComboItem(
int id,
string name)
{
Id = id;
Name = name;
}
public override string ToString()
{
return Name;
}
}
7. 商品一覧ロード
private void LoadProducts()
{
dgvProducts.Rows.Clear();
using SqliteConnection conn =
DbHelper.GetConnection();
conn.Open();
string sql =
@"
SELECT
p.Id,
p.ProductName,
c.CategoryName,
p.Note
FROM Products p
INNER JOIN Categories c
ON p.CategoryId = c.Id
ORDER BY p.ProductName
";
using SqliteCommand cmd =
new SqliteCommand(sql, conn);
using SqliteDataReader reader =
cmd.ExecuteReader();
while (reader.Read())
{
dgvProducts.Rows.Add(
reader["Id"],
reader["ProductName"],
reader["CategoryName"],
reader["Note"]);
}
}
8. 追加
private void btnAddProduct_Click(
object sender,
EventArgs e)
{
if (string.IsNullOrWhiteSpace(
txtProductName.Text))
{
MessageBox.Show(
"商品名を入力してください。");
return;
}
ComboItem category =
(ComboItem)cboProductCategory.SelectedItem;
using SqliteConnection conn =
DbHelper.GetConnection();
conn.Open();
string sql =
@"
INSERT INTO Products
(
ProductName,
CategoryId,
Note
)
VALUES
(
@ProductName,
@CategoryId,
@Note
)
";
using SqliteCommand cmd =
new SqliteCommand(sql, conn);
cmd.Parameters.AddWithValue(
"@ProductName",
txtProductName.Text);
cmd.Parameters.AddWithValue(
"@CategoryId",
category.Id);
cmd.Parameters.AddWithValue(
"@Note",
txtProductNote.Text);
cmd.ExecuteNonQuery();
LoadProducts();
}
9. 更新
選択行のIDを保持
private int _productId;
行クリック
private void dgvProducts_CellClick(
object sender,
DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0)
{
return;
}
DataGridViewRow row =
dgvProducts.Rows[e.RowIndex];
_productId =
Convert.ToInt32(
row.Cells[0].Value);
txtProductName.Text =
row.Cells[1].Value?.ToString();
txtProductNote.Text =
row.Cells[3].Value?.ToString();
SelectCategoryByName(
row.Cells[2].Value?.ToString());
}
更新
private void btnUpdateProduct_Click(
object sender,
EventArgs e)
{
ComboItem category =
(ComboItem)cboProductCategory.SelectedItem;
using SqliteConnection conn =
DbHelper.GetConnection();
conn.Open();
string sql =
@"
UPDATE Products
SET ProductName = @ProductName,
CategoryId = @CategoryId,
Note = @Note
WHERE Id = @Id
";
using SqliteCommand cmd =
new SqliteCommand(sql, conn);
cmd.Parameters.AddWithValue(
"@Id",
_productId);
cmd.Parameters.AddWithValue(
"@ProductName",
txtProductName.Text);
cmd.Parameters.AddWithValue(
"@CategoryId",
category.Id);
cmd.Parameters.AddWithValue(
"@Note",
txtProductNote.Text);
cmd.ExecuteNonQuery();
LoadProducts();
}
10. 削除
private void btnDeleteProduct_Click(
object sender,
EventArgs e)
{
if (_productId <= 0)
{
return;
}
if (MessageBox.Show(
"削除しますか?",
"確認",
MessageBoxButtons.YesNo)
!= DialogResult.Yes)
{
return;
}
using SqliteConnection conn =
DbHelper.GetConnection();
conn.Open();
string sql =
@"
DELETE
FROM Products
WHERE Id = @Id
";
using SqliteCommand cmd =
new SqliteCommand(sql, conn);
cmd.Parameters.AddWithValue(
"@Id",
_productId);
cmd.ExecuteNonQuery();
LoadProducts();
}
11. OCRとの連携(おすすめ)
商品マスタを追加したら、OCR取込時にカテゴリを自動設定できます。
例:
string category =
ProductRepository
.FindCategory(
productName);
爽健美茶
↓
商品マスタ検索
↓
飲料
↓
カテゴリ自動入力
となり、OCR後の修正作業がかなり減ります。
次の段階としては、支出登録画面で商品名入力時に商品マスタから候補表示(オートコンプリート) を実装すると使い勝手が大きく向上します。
動作確認
最後に
次回はマスタインポートを実装します。

