数据绑定

LINQ to SQL 支持绑定到常见控件,例如网格控件。 具体而言,LINQ to SQL 将定义用于绑定到数据网格和处理主-从绑定的基本模式,这两者都与显示和更新有关。

基本原理

LINQ to SQL 将 LINQ 查询转换为 SQL,以便在数据库上执行。 所得结果为强类型化的 IEnumerable。 由于这些对象是普通的公共语言运行时 (CLR) 对象,因此可以使用普通对象数据绑定来显示结果。 另一方面,更改作(插入、更新和删除)需要其他步骤。

操作

隐式绑定到 Windows 窗体控件是通过实现 IListSource 完成的。 数据源泛型 Table<TEntity>Table<T> 在 C# 或 Table(Of T) Visual Basic 中)和泛型 DataQuery 已更新以实现 IListSource。 用户界面(UI)数据绑定引擎(Windows 窗体和 Windows Presentation Foundation)都测试其数据源是否实现 IListSource。 因此,将查询的直接影响结果写入控件的数据源的操作会隐式调用 LINQ to SQL 集合生成,如以下示例所示:

DataGrid dataGrid1 = new DataGrid();
DataGrid dataGrid2 = new DataGrid();
DataGrid dataGrid3 = new DataGrid();

var custQuery =
    from cust in db.Customers
    select cust;
dataGrid1.DataSource = custQuery;
dataGrid2.DataSource = custQuery;
dataGrid2.DataMember = "Orders";

BindingSource bs = new BindingSource();
bs.DataSource = custQuery;
dataGrid3.DataSource = bs;
Dim dataGrid1 As New DataGrid()
Dim dataGrid2 As New DataGrid()
Dim dataGrid3 As New DataGrid()

Dim custQuery = _
    From cust In db.Customers _
    Select cust

dataGrid1.DataSource = custQuery
dataGrid2.DataSource = custQuery
dataGrid2.DataMember = "Orders"

Dim bs = _
    New BindingSource()
bs.DataSource = custQuery
dataGrid3.DataSource = bs

Windows Presentation Foundation 也是如此:

ListView listView1 = new ListView();
var custQuery2 =
    from cust in db.Customers
    select cust;

ListViewItem ItemsSource = new ListViewItem();
ItemsSource = (ListViewItem)custQuery2;
Dim listView1 As New ListView()
Dim custQuery2 = _
From cust In db.Customers _
Select cust

Dim ItemsSource As New ListViewItem
ItemsSource = custQuery2

泛型 Table<TEntity> 和泛型 DataQueryGetList 中实现了集合代系。

IListSource 实现

LINQ to SQL 在两个位置实现 IListSource

  • 数据源为 Table<TEntity>:LINQ to SQL 浏览表以填充在该表中保留引用的 DataBindingList 集合。

  • 数据源为 IQueryable<T>。 有两种情况:

    • 如果 LINQ to SQL 从 Table<TEntity> 中找到基础 IQueryable<T>,则源允许编辑,这种情形与第一条要点中的情形相同。

    • 如果 LINQ to SQL 找不到基础Table<TEntity>,则源不允许编辑(例如 groupby)。 LINQ to SQL 浏览查询以填充泛型 SortableBindingList,这是一个简单的 BindingList<T>,它为给定属性的 T 实体实现排序功能。

专用集合

对于本文档前面所述的许多功能,BindingList<T> 已被专门适用于一些不同的类。 这些类是泛型 SortableBindingList 类和泛型 DataBindingList类。 这两种类都声明为内部类。

泛型 SortableBindingList

此类继承自 BindingList<T>,是 BindingList<T> 的可排序版本。 排序是内存中解决方案,永远不会联系数据库本身。 BindingList<T>实现IBindingList,但默认情况下不支持排序。 但是,BindingList<T>使用虚拟IBindingList方法实现。 您可以很容易地重写这些方法。 泛型SortableBindingList覆盖SupportsSortingCoreSortPropertyCoreSortDirectionCoreApplySortCoreApplySortCoreApplySort 调用,用于对给定属性的 T 项列表进行排序。

如果该属性不属于 T,则会引发异常。

为了实现排序,LINQ to SQL 将创建一个泛型 SortableBindingList.PropertyComparer 类,此类继承自泛型 IComparer.Compare,并为给定类型 T 实现一个默认比较器,并实现一个 PropertyDescriptor 和一个方向。 此类可以动态地创建 T 的 Comparer,其中 T 是 PropertyTypePropertyDescriptor。 然后,从静态泛型 Comparer中检索默认比较器。 使用反射获取默认实例。

泛型 SortableBindingList 也是 DataBindingList 的基类。 泛型 SortableBindingList 提供两种可用于开始或停止跟踪项添加/删除的虚拟方法。 这两种方法可用于排序等基本功能,但实际上将由泛型 DataBindingList等上层类实现。

泛型 DataBindingList

此类继承自泛型 SortableBindingLIst。 泛型 DataBindingList 保留对用于在最初填充集合的泛型 Table 的基础泛型 IQueryable 的引用。 泛型 DatabindingList 通过重写 InsertItem() 和 RemoveItem() 将对项添加/移除操作的跟踪添加到集合。 它还实现了抽象暂停/恢复跟踪功能,使跟踪具有条件性。 此功能使泛型 DataBindingList 利用父类跟踪功能的所有多态用法。

绑定到 EntitySet

绑定到EntitySet是一种特殊情况,因为EntitySet已经是一个实现IBindingList的集合。 LINQ to SQL 添加了排序和取消 (ICancelAddNew) 支持。 类 EntitySet 使用内部列表来存储实体。 此列表是基于泛型数组(泛型 ItemList 类)的低级别集合。

添加排序功能

数组提供一个可与 T 的 Array.Sort() 一起使用的排序方法 (Comparer)。LINQ to SQL 使用本主题前面部分介绍的泛型 SortableBindingList.PropertyComparer 类来获取属性的此 Comparer 以及排序方向。 将 ApplySort 方法添加到泛型 ItemList 以调用此功能。

EntitySet 端,您现在必须声明排序支持:

使用 System.Windows.Forms.BindingSource 并将 EntitySet<TEntity> 绑定到 System.Windows.Forms.BindingSource.DataSource 时,必须调用 EntitySet<TEntity>.GetNewBindingList 来更新 BindingSource.List。

如果使用 System.Windows.Forms.BindingSource,设置 BindingSource.DataMember 属性,并将 BindingSource.DataSource 设置为具有名为 BindingSource.DataMember 的属性(该属性公开 EntitySet<TEntity>)的类,则无需调用 EntitySet<TEntity>.GetNewBindingList 来更新 BindingSource.List,但将失去排序功能。

缓存

LINQ to SQL 查询实现 GetList。 当 Windows 窗体 BindingSource 类满足此接口时,它会为单个连接调用 GetList() 三次。 为了解决此问题,LINQ to SQL 实现每个实例的缓存来存储和始终返回相同的生成集合。

取消

IBindingList AddNew定义控件用于从绑定集合创建新项的方法。 当最后一个可见行的标题中包含星形时,该DataGridView控件能够很好地展示这一功能。 星形符号显示您可以添加一个新项目。

除此功能外,集合还可以实现 ICancelAddNew。 此功能允许控件取消或验证新编辑的项目是否已验证。

在所有 LINQ to SQL 数据绑定集合(泛型 ICancelAddNew 和泛型 SortableBindingList)中实现 EntitySet。 在这两个实现中,代码执行如下作:

  • 允许插入项,然后从集合中删除项。

  • 只要 UI 不提交版本,就不会跟踪更改。

  • 只要版本被取消(CancelNew)就不会跟踪更改。

  • 允许在提交 (EndNew) 编辑内容时进行跟踪。

  • 如果新项不是来自 AddNew,则集合的行为正常。

故障排除

本部分将调用多个有助于对 LINQ to SQL 数据绑定应用程序进行故障排除的项。

  • 必须使用属性;仅使用字段是不够的。 Windows 窗体需要这种用法。

  • 默认情况下,imagevarbinarytimestamp数据库类型映射到字节数组。 由于 ToString() 在此方案中不受支持,因此无法显示这些对象。

  • 映射到主键的类成员具有 setter,但 LINQ to SQL 不支持对象标识更改。 因此,无法在数据库中更新映射中使用的主/唯一键。 在调用 SubmitChanges时,网格中的更改会导致异常。

  • 如果实体绑定到两个单独的网格(例如,一个主网格和另一个详细信息),则主网格中的实体 Delete 不会传播到详细信息网格。

另请参阅