VieTopik
Tiếng HànTiếng AnhIT
  • Góc học tập
Tải app
  • Thư viện
  • Luyện thi
  • Cẩm nang
  • Góc học tập
WinForms với OracleKết nối Oracle
Bài 12/15
5 phút

Master-detail

Nội dung bài · 5 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt

Màn hình đơn hàng cần hai bảng: trên là danh sách đơn, dưới là các dòng hàng của đơn đang chọn. Chọn đơn khác thì bảng dưới đổi theo. Bài này ghép quan hệ một-nhiều của EF Core với hai BindingSource để làm việc đó.

Khái niệm

🗂️ Master-detail (chính-phụ): màn hình hai phần, chọn một dòng ở bảng chính (master) thì bảng phụ (detail) hiện các dòng con của nó.

🧷 DataMember: tên property danh sách con mà BindingSource phụ lấy ra từ dòng đang chọn của BindingSource chính.

Đây vẫn là quan hệ một-nhiều giữa orders và order_lines ở khoá SQL, đã khai báo thành Order.Lines ở khoá ASP.NET Core. Bài này đưa nó lên màn hình.

Ví dụ

Chép class Order, OrderLine và hai DbSet Orders, OrderLines từ bài Quan hệ một-nhiều của khoá ASP.NET Core vào code. Đơn mẫu đã được tạo bằng POST /api/orders/sample ở bài đó. Muốn có thêm đơn thì gọi lại API này.

using Microsoft.EntityFrameworkCore;

class MainForm : Form
{
    private readonly ShopDbContext _db;
    private readonly BindingSource _orders =
        new BindingSource();
    private readonly BindingSource _lines =
        new BindingSource();

    public MainForm(ShopDbContext db)
    {
        _db = db;
        Text = "Đơn hàng";
        Width = 600;
        Height = 450;

        var ordersGrid = new DataGridView
        {
            Dock = DockStyle.Top,
            Height = 150,
            DataSource = _orders,
            ReadOnly = true,
            AllowUserToAddRows = false
        };
        var linesGrid = new DataGridView
        {
            Dock = DockStyle.Fill,
            DataSource = _lines,
            ReadOnly = true,
            AllowUserToAddRows = false
        };
        Controls.Add(linesGrid);
        Controls.Add(ordersGrid);

        Load += async (sender, e) =>
        {
            _orders.DataSource = await _db.Orders
                .Include(o => o.Lines)
                .ToListAsync();
            _lines.DataSource = _orders;
            _lines.DataMember = "Lines";
        };
    }
}
  • Include(o => o.Lines) đọc đơn kèm các dòng hàng, như ở khoá ASP.NET Core.
  • _lines.DataSource = _orders và DataMember = "Lines": danh sách dưới là Lines của đơn đang chọn ở trên.
  • Lưới trên chỉ có cột Id, CustomerId. Property danh sách Lines không thành cột.
DataMember = Lines BindingSource đơn Lưới đơn BindingSource dòng Lưới dòng hàng
Chọn đơn ở trên, lưới dưới hiện Lines của đơn đó

Thử ngay

Xoá dòng .Include(o => o.Lines) rồi chạy lại.

Đoán trước khi chạy: lưới dưới hiện các dòng hàng, báo lỗi, hay trống?

Xem kết quả
Lưới trên vẫn đủ các đơn.
Lưới dưới trống, dù chọn đơn nào.

Không có Include, EF Core chỉ đọc bảng ORDERS. Lines của mỗi đơn vẫn là list rỗng từ lúc khởi tạo, giống kết quả Thử ngay ở bài Quan hệ một-nhiều của khoá ASP.NET Core.

Lỗi hay gặp

Đặt DataMember trước khi có dữ liệu. Lúc đó _orders chưa có DataSource, nên BindingSource không biết Lines là gì. App dừng ngay khi mở với ArgumentException: không tìm thấy DataMember tên Lines.

// SAI — đặt trong constructor, _orders còn rỗng
_lines.DataSource = _orders;
_lines.DataMember = "Lines";
// ĐÚNG — đặt sau khi _orders đã có danh sách đơn
_orders.DataSource = await _db.Orders
    .Include(o => o.Lines)
    .ToListAsync();
_lines.DataSource = _orders;
_lines.DataMember = "Lines";

Tóm tắt

  • Master-detail: chọn dòng ở bảng chính, bảng phụ hiện các dòng con.
  • BindingSource phụ lấy DataSource là BindingSource chính, DataMember là tên property danh sách con.
  • Phải Include danh sách con, nếu không bảng phụ luôn trống.
  • Đặt DataMember sau khi BindingSource chính đã có dữ liệu.

Tự kiểm tra

0/3 câu
Câu 1

Màn hình khách hàng: trên là khách, dưới là đơn của khách đó (Customer.Orders). BindingSource _customerOrders cần gì?

Câu 2

Chọn đơn khác ở lưới trên thì lưới dưới đổi theo. Việc đổi đó do đâu?

Câu 3

Form đang mở thì có người tạo thêm một đơn qua API. Lưới đơn trên form thì sao?

CRUD với DataGridViewTách giao diện và dữ liệu

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt