实体(Row)

    不同于完全成熟的ORM,如 NHibernate/Entity Framework,Serenity 提供智能感知地映射和查询数据库所需的最小功能、编译时检查和容易的重构。

    Serenity 的实体通常像 XYZRow 这样命名。它们是 Serenity.Data.Row 子类。

    让我们来定义一个简单的行类:

    让我们先学习行的声明部分。

    我们在这里定义了一个名为 SimpleRow 的实体,它可能映射数据库中名为 Simple 的表。

    这里的 Row 后缀不是必须的,但通常加上该后缀可避免与其他的类名称发生冲突。

    我们现在声明第一个属性。此属性映射到数据库的 SimpleName 列。

    这里不能使用自动属性(如 get; set;)。必须通过称为 Field 的特定对象来读取和设置字段的值。

    Field 对象非常类似于 WPF 的依赖属性。下面是依赖属性的声明示例:

    1. public static readonly DependencyProperty MyCustomProperty =
    2. DependencyProperty.Register("MyCustom", typeof(string), typeof(Window1));
    3. {
    4. get { return this.GetValue(MyCustomProperty) as string; }
    5. set { this.SetValue(MyCustomProperty, value); }
    6. }

    我们在这里定义了一个静态依赖属性对象(MyCustomProperty),它包含属性元数据可以允许我们通过 GetValueSetValue 方法读取和设置属性的值。依赖属性允许 WPF 提供验证、 数据绑定、 动画及更多的功能。

    类似于依赖属性,Field 对象包含列的元数据和一些如任务跟踪(assignment tracking)、不使用表达式树构建的查询、变更通知等辅助功能。

    虽然依赖属性被声明为所使用类的静态成员, Field 对象在一个名为 RowFields 的嵌套类中声明。这样可更容易分组和获取引用,而不用添加 FieldProperty 后缀,并从实体中保持清晰的字段声明。

    这是我们的第二个属性: Int32? 类型的 Age

    Serenity 实体属性始终是可空的,即使数据库中的列类型不是可空类型。

    一个非空字段不可能有 null 值,但如果通过 left/right 联接查询呢?在这种情况下,如果检索到的值是 null 或 0 ,你要怎么处理呢?

      我们注意到,Field 对象在名为 RowFields(通常)嵌套子类中声明。在这里,我们创建它的唯一静态实例。因此,每个行类型(row type)只有一个 RowFields 实例,并且每个行属性(row property)只有一个 Field 实例 。

      Init 是初始化 RowFields 成员的扩展方法,它将创建没有显式初始化的 Field 对象。

      现在我们定义 SimpleRow 带参数的构造函数。基类 Row 需要一个 RowFields 实例,我们为其传递静态对象 Fields 。因此,行类型(SimpleRow)的所有实例共享单个 RowFields (SimpleRow.RowFields) 实例。这意味着它们共享所有元数据。

      1. public class RowFields : RowFieldsBase
      2. {
      3. public StringField Name;
      4. public Int32Field Age;

      我们在这里定义包含字段对象的嵌套类。它继承自 。RowFieldsBase 是一个与 Row 相关的特殊类,包含表的元数据。

      我们分别声明一个 StringFieldInt32Field 类型的字段。它们的类型基于其属性的类型,并且必须完全匹配。

      它们的名称必须与属性名称匹配,否则你将得到一个初始化错误。

      我们没有初始化这些字段对象,因此它们的初始值为 null。