65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 CSLA DynamicRootList 创建主/明细 DGV - 第一部分

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2009 年 3 月 12 日

CPOL

7分钟阅读

viewsIcon

47685

downloadIcon

1490

本项目展示了如何使用 CSLA EditableRootListBase(或 DynamicRootList)作为主列表对象来创建主/明细 DataGridView。它展示了如何在主从 DataGridView 上实现列表排序和自动保存。

Fig. Screenshot of Warehouse DGV

1. 引言

CSLA 是一个适用于 .NET Framework 2.0、3.0 和 3.5 的免费三层框架。CslaGenCSLA 的代码生成器。关于 CSLACslaGen,请参阅如何使用 CslaGen 生成 CSLA 数据访问层代码

这个项目诞生于我试图证明这是不可能完成的时候。嗯……事情总是这样发生的。:)

它展示了如何使用 CSLA DynamicRootListEditableRootListBase(简称 ERLB)作为主列表对象来创建主/明细 DataGridView(简称 DGV)。如果您使用 ERLB 作为主列表,自动保存是标准功能。本项目还展示了如何在明细列表中实现自动保存。作为奖励,您还可以获得两个列表的排序功能。

本项目详细展示了一个 CslaGen 项目的示例,并讨论了所有主要问题。截至(2009 年 3 月),CslaGen 尚不支持 DynamicRootList 的生成。另外,作为一个附加功能,您可以查看将 CslaGen 对象类型 EditableRootCollection + EditableSwitchable 转换为正确的 CSLA DynamicRootList + DynamicRoot 所需的更改。

1.1. 技术细节

  • CslaGen 没有版本号。我使用了一个稍作定制的版本(包括更改过的模板文件),您可以在这里下载。
  • 解决方案在 *References* 文件夹下包含了 CSLA 3.0.5 对象代码。
  • 该解决方案基于 .NET Framework 2.0 和 Visual Studio 2008 构建。
  • 本项目使用了 Microsoft SQL Server 2005,但您也可以使用 Express 版本。

2. 背景

CSLA 框架有不同类型的对象,而 EditableRootListBase(或 DynamicRootList)是最后加入该框架的。它专门设计用于与 Windows Forms DGV 进行数据绑定。在 CSLA 中,对象遵循一些约定。我只指出与本项目相关的部分。

  • 根对象是唯一可以独立加载和保存的对象类型。
  • 子对象由其父对象(无论是根对象还是另一个子对象)加载和保存。
  • 通常,子对象不引用其父对象(也不应该需要)。
  • ERLB 是一个例外,因为它是一个由根对象组成的根列表对象。
  • 您可以在常用术语表中找到更多详细信息。
  • EditableRootList 是一个对象列表。这些对象必须是子对象。假设您有一个员工列表,它是一个 EditableRootList。每个员工都是一个 EditableChild。一旦您编辑了员工数据(员工是一个子对象),要保存它,您必须保存整个员工列表(根)。这并不可行。通常的做法是有一个根只读列表,其中包含所有员工,您可以选择要编辑的员工作为根对象(一个独立的对象,不是根只读列表的子对象)。但这与 DGV 的工作方式不同。因此,一种新型对象应运而生:
    • EditableRootListBase,一个根对象集合
  • ERLB 是一个根集合,它加载对象,但允许您单独保存每个对象,即集合中的每个对象都是一个根对象。这符合 DGV 的行为,即在您移动到另一行时会立即保存每一行。

    2.1. 名称的含义?

    我花了一些功夫才理解“不那么常用的术语”,但这个问题不像您想象的那么简单,因为它揭示了关于 ERLB 的重要信息。CSLA 模板现在包括 DynamicRootListDynamicRoot。如前所述,我们知道 DynamicRootList 就是 ERLB 的另一个名称。但 DynamicRoot 是什么?为什么我们不能使用 EditableRoot 模板?事实上,ERLB 使用根对象,但不是普通的 editable root 对象,因为它们的加载方式类似于 editable child 的加载方式。事实证明,CslaGen 对象类型 EditableSwitchable 可以同时作为 editable root 和 editable child 加载。正如我们稍后将看到的,使用 CslaGen 对象类型 EditableRootCollection + EditableSwitchable 是最接近 DynamicRootList + DynamicRoot 生成的方式,因为它只需要进行一些小的更改即可完成工作。

    为了简化起见,从现在开始,我们将只使用 DynamicRootList,并省略 EditableRootListBaseERLB 的名称。同样,我们将只使用 DynamicRoot,并省略 EditableRoot

    3. 其他值得关注的点

    大多数人会参考 ProjectTracker 来了解 CSLA 的使用示例。除了 DynamicRootList 的全面示例外,本文还提供了另一个使用示例来源。您可能会发现这些示例很有趣:

    • 使用 SortedBindingListDataGridView 进行排序
    • 使用新语法使用 AddBusinessRules
    • 使用 System.Threading.Interlocked.Decrement 为新对象获取唯一的临时 ID
    • 乐观并发和 DataPortal 事件(CslaGen 中的标准功能)
    • 完整的 CslaGen 项目文档,讨论了所有不太明显的选项(请参阅附录以获取完整的屏幕截图集合)

    4. 使用场景

    对于这个示例项目,我选择了“品牌与型号”这个主题。每个品牌是几个型号的父级,并且没有型号是两个品牌的子级。不允许有两个同名的品牌。对于给定的品牌,不允许有两个同名的型号,尽管同一型号名称可以存在于不同的品牌中。请注意,名称匹配时不区分大小写。

    由于我打算使其可重用,因此在 UI(用户界面)层面,名称都围绕着“主”和“明细”。在 BO(业务对象)层面,我使用实际的对象名称。为了重用它,您只需要将 BrandCollBrandModelCollModel 替换为您自己的对象名称。为了使其更具可重用性,您应该将其制作成组件。

    5. 数据库

    Warehouse 数据库有一个用于品牌的表,另一个用于型号的表。BrandID 是型号表的外键。

    Fig. 1 - Warehouse database diagram
    图 1 - Warehouse 数据库图。

    SQL Server 中,Price 列定义为 money 类型。对于 .NET Framework,使用的数据类型是 Decimal

    CslaGen 会自动支持乐观并发,如果您包含一个 timestamp 数据类型的 SQL 列。尽管有这个名称,这种数据类型与时间无关,实际上是一个版本计数器,从零开始,并且在每次行更新时递增。这就是为什么我更喜欢称之为 RowVersion。乐观并发会检查当前行版本是否与对象获取时行的版本匹配,如果不匹配,则拒绝保存,并警告您该对象已被更改。这意味着其他用户已更改或删除了它。

    SQL Server 中运行脚本来创建数据库和表。同时,也请运行脚本来创建存储过程。项目文件 *CslaERLB1.zip* 包含所有脚本。您将使用编译后的源代码自行填充数据库。

    6. 对象

    尽管 CslaGen 尚不支持 DynamicRootList,但 CslaGen 文件(*Warehouse.xml*)已包含在 *CslaERLB1.zip* 中。我使用了 CslaGen 对象类型 EditableRootCollectionEditableSwitchable。然后我修改了生成的文件,并将它们转换成了一组正确的 DynamicRootList + DynamicRoot 对象(CSLA 模板命名)。

    Fig. 2 - Warehouse object diagram
    图 2 - Warehouse 对象图(仅显示非生成对象)。

    BrandCollBrand 对象的根集合。它是一个 DynamicRootList,一个由 DynamicRoot 对象组成的集合。因此,Brand 也是一个根对象。Brand 对象是 ModelColl 集合的父级,而 ModelCollModel 对象的集合。

    注释

    • 嵌套类型是对象的条件。
    • static 字段 _lastID 用作临时 ID 的种子,用于在新对象提交到数据库并获取实际 ID(由数据库提供)之前。
    • AddBusinessRules 方法负责将验证规则添加到对象中。CslaGen 对验证规则有一定的支持。但我更喜欢自己处理。在这种情况下,它使用了新语法(自 CSLA 2.1 起)。
    • NoDuplicates 方法是一个验证规则,根据 4. Use cases 中所述的规则,检查名称是否已存在于集合中。
    • 为了使用 DGV,每个集合都必须有一个 AddNewCore 方法。

    本文的其他部分

    历史

    • 文档版本 1:2009 年 3 月 12 日
    • 代码版本 1.1: 2009 年 3 月 14 日 - 错误修正
  • © . All rights reserved.