0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIに頼り切って家計簿アプリを追加開発する。:商品マスタ実装

0
Last updated at Posted at 2026-06-04

はじめに

前回までで、家計簿アプリが一旦完成しました。(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後の修正作業がかなり減ります。

次の段階としては、支出登録画面で商品名入力時に商品マスタから候補表示(オートコンプリート) を実装すると使い勝手が大きく向上します。

動作確認

実際起動するとこうなります。
image.png
image.png

最後に

次回はマスタインポートを実装します。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?