# 实体关系

实体关系可用于数据访问中的关联查询(joins)和展开查询(expand),如在关联查询时只需指定关系名,便能在生成SQL中根据关系的目标实体及关联字段,拼接生成对应的表名、及列。目前支持定义的关系有:多对一关系,一对多关系。

关系注解映射类见:fly.data.relational.mapping.forclass.SimpleRelationMapper

关系处理类见:fly.data.relational.mapping.processor.RelationMappingProcessor

# 多对一关系

在实体类上或实体字段上使用@ManyToOne注解,定义多对一关系。如成员与组织为两个实体之间的多对一关系,子组织与父组织为同一个实体的多对一关系。

  • 作用于实体类,需要明确关联的字段及关系名
import fly.core.data.annotation.JoinField;
import fly.core.data.annotation.ManyToOne;

@Entity
@ManyToOne(targetEntity = Org.class, optional = true, relation = "parent", fields = {
    @JoinField(name = "parentId", referencedFieldName = "id")
})
public class Org {
    
    @UUID
    protected String id;
    
    @Column
    protected String parentId;
    
    // get/set
    
}
  • 作用于实体字段,定义更加简洁
import fly.core.data.annotation.ManyToOne;

@Entity
public class Org {
    
    @UUID
    protected String id;
    
    // 默认关联到目标实体的主键字段,即 parentId -> id
    // 默认关系名根据字段会解析为 parent
    @ManyToOne(targetEntity = Org.class, optional = true)
    protected String parentId;
    
    // get/set
    
}

@ManyToOne注解属性简单说明:

注解属性 说明 类型 默认值
targetEntity 必填,等同于注解的value,定义关系目标实体类 Class<?> -
relation 关系名 String 1. 注解作用于实体类时,默认关系名为目标实体名的首字母小写;2. 若注解作用于字段,如在authorId字段上添加关系,关联字段为Author实体的id,则关系名为author。其他情况则为字段名,关系名不建议与字段名重复,此时应自定义关系名
fields 关联字段 JoinField[] 若注解作用于字段,默认为当前字段关联目标实体的主键
optional 关系是否可选,影响关联查询时使用LEFT JOINtrue)还是JOIN boolean true
expandable 该关系是否可展开查询 boolean true
defaultExpanding 展开查询时默认返回的字段 String[] 关系实体所有可查询字段
generateForeignKey ddlAuto时是否产生外键约束 boolean true
foreignKeyName ddlAuto时产生的外键约束名称 String fk_{entityName}_{relationName}

# 一对多关系

在实体类上添加@OneToMany注解定义一对多关系,定义前需要目标实体先存在与本实体的多对一关系

下示例中,子组织对父组织为多对一关系,已在parentId字段上定义;而父组织对子组织为一对多关系,在实体类上定义:

import fly.core.data.annotation.OneToMany;

@Entity
@OneToMany(name = "children", targetEntity = Org.class, defaultExpanding = {"name"})
public class Org {
    
    @UUID
    protected String id;
    
    @ManyToOne(targetEntity = Org.class, optional = true)
    protected String parentId;
    
    // get/set
    
}

@OneToMany注解属性简单说明:

注解属性 说明 类型 默认值
name 必填,关系名 String -
targetEntity 必填,关系目标实体类 Class<?> -
inverseRelation 若目标实体类有多个关联到本实体的多对一关系,则需要用该属性明确指定是用哪个多对一关系 String 默认取目标实体关联到本实体的唯一一个多对一关系
expandable 该关系是否可展开查询 boolean true
defaultExpanding 展开查询时默认返回的字段 String[] 关系实体所有可查询字段
optional 关系是否可选,影响关联查询时使用LEFT JOINtrue)还是JOIN boolean false

# 多对多关系

多对多关系目前支持下列两种场景:

  1. 存在中间表实体,中间表包含两个外键,分别关联两个实体;
  2. 不存在中间实体,但是当前实体存在关系实体的ids列表字段,我们称为内嵌关系字段;

# 中间表实体

设从 User 用户实体到 Role 角色实体建立多对多关系,UserRole 为中间表,UserRole 包含两个多对一关系,分别关联 User 和 Role:

User 实体:

import fly.core.data.annotation.ManyToMany;

@Entity
@ManyToMany(name = "roles", targetEntity = Role.class, joinEntity = UserRole.class, defaultExpanding = { "code" })
public class User {

    @UUID
    protected String id;

    // get/set

}

Role 实体:

@Entity
public class Role {

    @UUID
    protected String id;

    @Column(length = 10)
    protected String code;

    // get/set

}

UserRole 实体,:

@Entity
public class UserRole {

    @UUID
    protected String id;

    @ManyToOne(targetEntity = User.class)
    protected String userId;

    @ManyToOne(targetEntity = Role.class)
    protected String roleId;

    // get/set

}

# 内嵌关系字段

设从 User 用户实体到 Role 角色实体建立多对多关系,User 实体存在一 ids 字段,数据库存储的数据结构为:["id1","id2"]

User 实体:

import fly.core.data.annotation.ManyToMany;

@Entity
@ManyToMany(name = "roles", targetEntity = Role.class, embeddedField = "ids", defaultExpanding = { "code" })
public class User {

    @UUID
    protected String id;

    @Column(definition = "LONGVARCHAR")
    protected Set<String> ids;

    // get/set

}

Role 实体:

@Entity
public class Role {

    @UUID
    protected String id;

    @Column(length = 10)
    protected String code;

    // get/set

}
顶部