使用 Visual Studio 将对象绑定为 .NET Framework 应用程序中的数据源

注意

数据集和相关类是 2000 年代初的旧 .NET Framework 技术,使应用程序能够在应用程序与数据库断开连接时处理内存中的数据。 它们对于使用户能够修改数据并持续更改回数据库的应用程序特别有用。 虽然数据集已被证明是一项非常成功的技术,但我们建议新的 .NET 应用程序使用 Entity Framework Core。 实体框架提供了一种更自然的方式来将表格数据作为对象模型,并且具有更简单的编程接口。

Visual Studio 提供设计时工具以将自定义对象用作应用程序中的数据源。 若要将数据库中的数据存储在与 UI 控件绑定的对象中,建议的方法是使用实体框架生成类。 实体框架自动生成所有样本更改跟踪代码,这意味着当你在 DbSet 对象上调用 AcceptChanges 时,对本地对象的任何更改都会自动持续到数据库中。 有关详细信息,请参阅实体框架文档

提示

只有在应用程序已经基于数据集的情况下,才应考虑本文中对象绑定的方法。 如果你已熟悉数据集,将要处理的数据是表格数据,且不会太复杂或太大,则也可以使用这些方法。 有关更简单的示例,涉及使用 DataReader 将数据直接加载到对象中,以及手动更新 UI 而不进行数据绑定,请参阅使用 ADO.NET 创建简单的数据应用程序

对象要求

自定义对象与 Visual Studio 中的数据设计工具配合使用的唯一要求是对象至少需要一个公共属性。

通常,自定义对象不需要任何特定的接口、构造函数或属性来充当应用程序的数据源。 但是,如果要将对象从“数据源”窗口拖动到设计图面以创建数据绑定控件,并且如果对象实现 ITypedListIListSource 接口,则对象必须具有默认构造函数。 否则,Visual Studio 无法对数据源对象进行实例化,并且当你将项目拖到设计图面时,它会显示错误。

将自定义对象用作数据源的示例

虽然在将对象用作数据源时有无数方法可以实现应用程序逻辑,但对于 SQL 数据库,有几个标准操作可以通过使用 Visual Studio 生成的 TableAdapter 对象进行简化。 本页说明如何使用 TableAdapter 实现这些标准进程。 它并不用作创建自定义对象的指南。 例如,无论对象的具体实现或应用程序的逻辑如何,你通常都会执行以下标准操作:

  • 将数据加载到对象(通常从数据库数据库)。

  • 创建对象的类型集合。

  • 向集合添加对象以及从集合中删除对象。

  • 在窗体上向用户显示对象数据。

  • 更改/编辑对象中的数据。

  • 将数据从对象保存回数据库。

将数据加载到对象中

对于此示例,使用 TableAdapter 将数据加载到对象中。 默认情况下,使用两种从数据库获取数据并填充数据表的方法创建 TableAdapter。

  • TableAdapter.Fill 方法使用返回的数据填充现有数据表。

  • TableAdapter.GetData 方法返回填充了数据的新数据表。

使用数据加载自定义对象的最简单方法是调用 TableAdapter.GetData 方法,循环访问返回的数据表中的行集合,并使用每行中的值填充每个对象。 可以创建一个 GetData 方法,为添加到 TableAdapter 的任何查询返回填充的数据表。

注意

Visual Studio 默认情况下将 TableAdapter 查询命名为 FillGetData,但你可以将这些名称更改为任何有效的方法名称。

以下示例演示如何循环访问数据表中的行,并使用数据填充对象:

private void LoadCustomers()
{
    NorthwindDataSet.CustomersDataTable customerData = 
        customersTableAdapter1.GetTop5Customers();
    
    foreach (NorthwindDataSet.CustomersRow customerRow in customerData)
    {
        Customer currentCustomer = new Customer();
        currentCustomer.CustomerID = customerRow.CustomerID;
        currentCustomer.CompanyName = customerRow.CompanyName;

        if (customerRow.IsAddressNull() == false)
        {
            currentCustomer.Address = customerRow.Address;
        }

        if (customerRow.IsCityNull() == false)
        {
            currentCustomer.City = customerRow.City;
        }

        if (customerRow.IsContactNameNull() == false)
        {
            currentCustomer.ContactName = customerRow.ContactName;
        }

        if (customerRow.IsContactTitleNull() == false)
        {
            currentCustomer.ContactTitle = customerRow.ContactTitle;
        }

        if (customerRow.IsCountryNull() == false)
        {
            currentCustomer.Country = customerRow.Country;
        }

        if (customerRow.IsFaxNull() == false)
        {
            currentCustomer.Fax = customerRow.Fax;
        }

        if (customerRow.IsPhoneNull() == false)
        {
            currentCustomer.Phone = customerRow.Phone;
        }

        if (customerRow.IsPostalCodeNull() == false)
        {
            currentCustomer.PostalCode = customerRow.PostalCode;
        }

        if (customerRow.IsRegionNull() == false)
        {
            currentCustomer.Region = customerRow.Region;
        }

        LoadOrders(currentCustomer);
        customerBindingSource.Add(currentCustomer);
    }
}

创建对象的类型集合

你可以为对象创建集合类,或使用 BindingSource 组件自动提供的类型集合。

为对象创建自定义集合类时,建议从 BindingList<T> 继承。 此泛型类提供管理集合的功能,以及引发事件的功能,这些事件将通知发送到 Windows 窗体中的数据绑定基础结构。

BindingSource 中自动生成的集合使用 BindingList<T> 作为其类型集合。 如果应用程序不需要其他功能,则你可以在 BindingSource 中维护集合。 有关详细信息,请参阅 BindingSource 类的 List 属性。

注意

如果集合需要 BindingList<T> 的基础实现未提供的功能,则应创建自定义集合,以便根据需要添加到类。

以下代码演示如何为 Order 对象的强类型集合创建类:

/// <summary>
/// A collection of Orders
/// </summary>
public class Orders: System.ComponentModel.BindingList<Order>
{
    // Add any additional functionality required by your collection.
}

向集合添加对象

通过调用自定义集合类或 BindingSourceAdd 方法将对象添加到集合中。

注意

BindingList<T> 继承时,会自动为自定义集合提供 Add方法。

以下代码演示如何将对象添加到 BindingSource 中的类型集合:

Customer currentCustomer = new Customer();
customerBindingSource.Add(currentCustomer);

以下代码演示如何将对象添加到从 BindingList<T> 继承的类型集合:

注意

在此示例中,Orders 集合是 Customer 对象的属性。

Order currentOrder = new Order();
currentCustomer.Orders.Add(currentOrder);

从集合中删除对象

通过调用自定义收集类或 BindingSourceRemoveRemoveAt 方法,从集合中删除对象。

注意

BindingList<T> 继承时,会自动为自定义集合提供 RemoveRemoveAt 方法。

下列代码显示了如何使用 RemoveAt 方法在 BindingSource 中定位和删除类型集合中的对象:

int customerIndex = customerBindingSource.Find("CustomerID", "ALFKI");
customerBindingSource.RemoveAt(customerIndex);

向用户显示对象数据

要向用户显示对象中的数据,请使用“数据源配置”向导创建对象数据源,然后从“数据源”窗口将整个对象或单个属性拖动到窗体 。

修改对象中的数据

若要编辑将数据绑定到 Windows 窗体控件的自定义对象中的数据,只需在绑定控件(或直接在对象属性中)中编辑数据即可。 数据绑定体系结构更新对象中的数据。

如果应用程序需要跟踪更改并回退其原始值建议的更改,则你必须在对象模型中实现此功能。 有关数据表如何跟踪建议的更改的示例,请参阅 DataRowStateHasChangesGetChanges

将对象中的数据保存回数据库

通过将对象中的值传递给 TableAdapter 的 DBDirect 方法,来将数据保存回数据库。

Visual Studio 创建可直接对数据库执行的 DBDirect 方法。 这些方法不需要 DataSet 或 DataTable 对象。

TableAdapter DBDirect 方法 说明
TableAdapter.Insert 将新记录添加到数据库,使你可以将单个列值作为方法参数传递。
TableAdapter.Update 更新数据库中的现有记录。 Update 方法采用原始列值和新列值作为方法参数。 原始值用于查找原始记录,新值用于更新该记录。

TableAdapter.Update 方法还用于通过将 DataSetDataTableDataRowDataRow 的数组作为方法参数,来协调返回数据库的数据集中的变化。
TableAdapter.Delete 基于作为方法参数传入的原始列值,从数据库中删除现有记录。

若要从对象集合中保存数据,则请循环访问对象集合(例如使用下一个循环)。 使用 TableAdapter 的 DBDirect 方法将每个对象的值发送到数据库。

以下示例演示如何使用 TableAdapter.Insert DBDirect 方法将新的客户直接添加到数据库中:

private void AddNewCustomers(Customer currentCustomer)
{
    customersTableAdapter.Insert( 
        currentCustomer.CustomerID, 
        currentCustomer.CompanyName, 
        currentCustomer.ContactName, 
        currentCustomer.ContactTitle, 
        currentCustomer.Address, 
        currentCustomer.City, 
        currentCustomer.Region, 
        currentCustomer.PostalCode, 
        currentCustomer.Country, 
        currentCustomer.Phone, 
        currentCustomer.Fax);
}