属性映射


  属性使用 PropertyMappingAttribute 特性进行标记。它包含以下的属性:

  • ColumnName 标记数据库表中的字段名称。

  • Description 标记字段的备注。

  • IsPrimaryKey 标记是否为主键。

  • GenerateType 设置主键的生成方式。

  • IsDeletedKey 标记是否为逻辑删除标记。

  • IsNullable 标记是否为可空,非必要,但是使用 CodeFirst 模式需要设置。

  • DataType 标记字段的类型,非必要,但是使用 CodeFirst 模式需要设置。

  • Length 标记字段的长度,非必要,但是使用 CodeFirst 模式需要设置。

  • Precision 标记字段的精度,非必要,但是使用 CodeFirst 模式需要设置。

  • Scale 标记字段的小数位,非必要,但是使用 CodeFirst 模式需要设置。

  • IsConcurrencyToken 标记并发控制标识。

  • IsRowVersion 标记行版本号。


  我们再来温习一下 实体模型 的实体类的定义,如下:

public partial class Products : LightEntity<Products>
{
    [PropertyMapping(ColumnName = "product_id", IsPrimaryKey = true, GenerateType = IdentityGenerateType.AutoIncrement, IsNullable = false)]
    public virtual int Id { get; set; }

    [PropertyMapping(ColumnName = "product_name", Length = 40, IsNullable = false)]
    public virtual string ProductName { get; set; }

    [PropertyMapping(ColumnName = "supplier_id", IsNullable = true)]
    public virtual int? SupplierID { get; set; }

    [PropertyMapping(ColumnName = "category_id", IsNullable = true)]
    public virtual int? CategoryID { get; set; }

    [PropertyMapping(ColumnName = "quantity_pre_unit", Length = 20, IsNullable = true)]
    public virtual string QuantityPerUnit { get; set; }

    [PropertyMapping(ColumnName = "unit_price", IsNullable = true)]
    public virtual decimal? UnitPrice { get; set; }

    [PropertyMapping(ColumnName = "units_in_stock", IsNullable = true, DefaultValue = 34)]
    public virtual short? UnitsInStock { get; set; }

    [PropertyMapping(ColumnName = "units_on_order", IsNullable = true)]
    public virtual short? UnitsOnOrder { get; set; }

    [PropertyMapping(ColumnName = "reorder_level", IsNullable = true)]
    public virtual short? ReorderLevel { get; set; }

    [PropertyMapping(ColumnName = "discontinued", IsNullable = false)]
    public virtual bool? Discontinued { get; set; }

    public virtual EntitySet<OrderDetails> OrderDetailses { get; set; }
}

  需要说明的是主键的 GenerateType 类型,大部分的数据库都有自增量,因此可以设置为 AutoIncrement,如果你需要手动指定主键值,则设为 None,比较特殊的情况如 Oracle 数据库,需要设为 Generator,此时,它会使用 标识生成服务 来生成。

  另外,关于逻辑删除标记,一旦标记了某一个属性后,其仓储的 删除实体 将执行逻辑删除,仅将属性标记为 true,后续的查询均会过滤掉已经逻辑删除的数据。

  行版本号和并发控制请参阅 行版本号及并发控制


💡 属性分类

  属性分基础属性 GeneralProperty、关联属性 RelationProperty 两种,关联属性又分为实体属性 EntityProperty、实体集属性 EntitySetProperty、枚举引用属性 EnumProperty 和 属性引用属性 ReferenceProperty


  使用 PropertyUnity 类可以获取指定实体类型某属性的元数据。它有以下方法:

  • GetProperties 获取实体类型的所有属性。

  • GetPrimaryProperties 获取实体类型的所有主键属性。

  • GetPersistentProperties 获取实体类型的所有可持久化属性,即排除关联属性之外的属性。

  • GetRelatedProperties 获取实体类型的所有关联属性。

  下面的示例演示了如何获取实体类的属性元数据:

[TestMethod]
public void TestGetProperty()
{
    //基础属性
    var property = PropertyUnity.GetProperty(typeof(Products), nameof(Products.ProductName));
    Assert.IsNotNull(property); //GeneralProperty
    Assert.AreEqual("product_name", property.Info.ColumnName);
    Assert.IsTrue(property.Info.IsNullable);
    
    //子实体集属性
    property = PropertyUnity.GetProperty(typeof(Products), nameof(Products.OrderDetailses));
    Assert.IsNotNull(property); //EntitySetProperty
    
    var relation = property as RelationProperty;
    Assert.AreEqual(typeof(OrderDetails), relation.RelationalType)
    
    //主键
    property = PropertyUnity.GetPrimaryProperties(typeof(Products)).FirstOrDefault();
    Assert.AreEqual(nameof(Products.Id), property.Name);
}

💡 小提示

  如果你的属性和字段的名称是一致的,那么除了主键需要打上 PropertyMappingAttribute 特性外,其他属性都是可以不用标记的。对于基于 LightEntity<TEntity> 类型的实体类,Fireasy 会自动查找 virtual 的属性进行映射。如果有其他的需要,你可以改变 EntityMetadataUnity 类的 PropertyMetadataResolver 属性,实现 IPropertyMetadataResolver 接口来进行个性化映射。