关系映射


  使用关系映射,使你在查询时会非常方便。你可以像 Entity Framework 的导航属性一样使用,也可以使用类似 Include 的方法带回关联的数据,因此,关系映射才是 ORM 最最核心的内容。

  关系映射早期是使用 RelationshipAttribute 特性来标记是,它用于 assembly 中,指定两个实体类之间的关系。如下所示:

[assembly: RelationshipAttribute("products:order_details", typeof(Products), typeof(OrderDetails), "Id=>ProductID")]
[assembly: RelationshipAttribute("orders:order_details", typeof(Orders), typeof(OrderDetails), "OrderID=>OrderID")]

  在 RelationshipAttribute 特性中,一般使用一对多方式进行映射,即 thisType 对应的是主表,otherType 对应的是子表,那么表达式采用 主键=>外键。当然有时候你可能会反着来,采用多对一的方式,那此时 thisType 对应的是子表,otherType 对应的是主表,表达式采用 外键<=主键。

  现在,你不必要再指定 RelationshipAttribute 特性了,Fireasy 做了以下约定:只需你子表的外键的命名为 主表(单数形式)+Id,即可自动映射上。如下所示:

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

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

public class OrderDetails : LightEntity<OrderDetails>
{
    [PropertyMapping(ColumnName = "product_id")]
    public virtual int ProductId { get; set; }
    
    [PropertyMapping(ColumnName = "order_id")]
    public virtual int OrderId { get; set; }
    
    public virtual Products Products { get; set; }
    
    public virtual Orders Orders { get; set; }
}

  如果无法遵守此约定,你也可以使用 RelationshipAssignAttribute 特性来指定所对应的主外键。如下所示:

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

public class OrderDetails : LightEntity<OrderDetails>
{
    /// <summary>
    /// 商品ID。
    /// </summary>
    [PropertyMapping(ColumnName = "product_id")]
    public virtual int ProdId { get; set; }
    
    [RelationshipAssign(nameof(Products.Id), nameof(OrderDetails.ProdId))]
    public virtual Products Products { get; set; }
}

  这在一个子表同时关联了两个以上同一主表的情况下非常有用。如下所示:

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

public class Orders : LightEntity<Orders>
{
    /// <summary>
    /// 录入人ID。
    /// </summary>
    [PropertyMapping(ColumnName = "record_emp_id")]
    public virtual int RecordEmpId { get; set; }
    
    /// <summary>
    /// 申请人ID。
    /// </summary>
    [PropertyMapping(ColumnName = "allpy_emp_id")]
    public virtual int ApplyEmpId { get; set; }

    /// <summary>
    /// 审核人ID。
    /// </summary>
    [PropertyMapping(ColumnName = "audit_emp_id")]
    public virtual int AuditEmpId { get; set; }
    
    /// <summary>
    /// 录入人。
    /// </summary>
    [RelationshipAssign(nameof(Employees.Id), nameof(Orders.RecordEmpId))]
    public virtual Employees RecordEmployee { get; set; }
    
    /// <summary>
    /// 申请人。
    /// </summary>
    [RelationshipAssign(nameof(Employees.Id), nameof(Orders.ApplyEmpId))]
    public virtual Employees ApplyEmployee { get; set; }
    
    /// <summary>
    /// 审核人。
    /// </summary>
    [RelationshipAssign(nameof(Employees.Id), nameof(Orders.AuditEmpId))]
    public virtual Employees AuditEmployee { get; set; }
}