Skip to content

数据模型关联

基本概念

Yao DSL支持两种数据模型关联类型:

  • hasOne:一对一关联,表示当前模型的一条记录对应关联模型的一条记录
  • hasMany:一对多关联,表示当前模型的一条记录对应关联模型的多条记录

通过使用withs参数,可以在查询时同时获取关联数据,避免多次查询,提高效率。

实例说明

以下我们通过供应商(supplier)和用户(user)两个模型演示关联关系:

  • 一个用户对应一家供应商 (用户 -> 供应商 = hasOne)
  • 一家供应商有多个用户 (供应商 -> 用户 = hasMany)

数据结构设计

供应商模型 (supplier)

字段结构

字段标签说明
idID主键
name名称供应商名称

示例数据

ID名称
1象传智慧
2Yao App Engine

用户模型 (user)

字段结构

字段标签说明
idID主键
supplier_id所属供应商 ID外键,关联供应商表
name姓名用户姓名

示例数据

IDsupplier_idname
11张无忌
21李光富
32李木婷
42赵长青

模型定义文件

供应商模型定义 (supplier.mod.json)

json
{
  "name": "供应商",
  "table": { "name": "supplier", "comment": "供应商表" },
  "columns": [
    {
      "label": "ID",
      "name": "id",
      "type": "ID",
      "comment": "ID"
    },
    {
      "label": "名称",
      "name": "name",
      "type": "string",
      "index": true,
      "comment": "供应商名称"
    }
  ],
  "relations": {
    "users": {
      "name": "users", // 关联名称,查询时通过此名称引用
      "type": "hasMany", // 关系类型:一对多
      "model": "user", // 关联的模型名称
      "key": "supplier_id", // 关联模型中的关联字段
      "foreign": "id", // 当前模型中的关联字段
      "query": { "select": ["id", "name"] } // 默认查询字段
    }
  },
  "values": [
    { "id": 1, "name": "象传智慧" },
    { "id": 2, "name": "Yao App Engine" }
  ]
}

用户模型定义 (user.mod.json)

json
{
  "name": "用户",
  "table": { "name": "user", "comment": "用户表" },
  "columns": [
    { "label": "ID", "name": "id", "type": "ID", "comment": "ID" },
    {
      "label": "供应商",
      "name": "supplier_id",
      "type": "bigInteger",
      "index": true,
      "comment": "供应商ID"
    },
    {
      "label": "姓名",
      "name": "name",
      "type": "string",
      "index": true,
      "comment": "用户姓名"
    }
  ],
  "relations": {
    "supplier": {
      "name": "supplier", // 关联名称,查询时通过此名称引用
      "type": "hasOne", // 关系类型:一对一
      "model": "supplier", // 关联的模型名称
      "key": "id", // 关联模型中的关联字段
      "foreign": "supplier_id", // 当前模型中的关联字段
      "query": { "select": ["id", "name"] } // 默认查询字段
    }
  },
  "values": [
    { "id": 1, "supplier_id": 1, "name": "张无忌" },
    { "id": 2, "supplier_id": 1, "name": "李光富" },
    { "id": 3, "supplier_id": 2, "name": "李木婷" },
    { "id": 4, "supplier_id": 2, "name": "赵长青" }
  ]
}

数据表创建

使用以下命令创建数据表:

bash
yao migrate

关联关系声明详解

关联关系通过模型定义中的 relations 对象声明,支持多个映射关系。

关联关系对象字段说明

字段类型必填说明
namestring关联名称,查询时的引用标识符
typestring关系类型:hasOne(一对一) 或 hasMany(一对多)
modelstring关联模型名称
keystring关联模型中用于关联的字段名称
foreignstring当前模型中用于关联的字段名称
queryobject关联模型的默认查询条件,可在实际查询时重载

hasOne 关联使用示例

hasOne 表示"拥有一个"关系,如用户拥有一个供应商的关联。

基本查询

查询用户并同时获取供应商信息:

bash
# 查询ID为1的用户及其供应商信息
yao run models.user.Find 1 '::{"withs":{ "supplier": {} }}'

# 查询所有用户及其供应商信息
yao run models.user.Get '::{"withs":{ "supplier": {} }}'

指定关联字段

bash
# 仅查询供应商的name字段
yao run models.user.Find 1 '::{"withs":{ "supplier": {"query":{ "select":["name"] }} }}'

按关联字段条件筛选

bash
# 查询供应商名称为"Yao App Engine"的用户
yao run models.user.Get '::{"withs":{ "supplier": {} }, "wheres":[{"rel":"supplier", "column":"name", "value":"Yao App Engine" }]}'

JavaScript中使用关联查询

javascript
function test() {
  var user = Process('models.user.get', {
    withs: {
      supplier: {
        // 关联供应商表
        query: {
          select: ['name', 'id'] // 指定查询字段
        }
      }
    },
    wheres: [{ column: 'supplier_id', value: 1, op: '=' }], // 查询条件
    orders: [{ column: 'id', option: 'desc' }], // 排序条件
    limit: 1 // 限制返回条数
  });
}

hasMany 关联使用示例

hasMany 表示"拥有多个"关系,如供应商拥有多个用户的关联。

基本查询

bash
# 查询ID为1的供应商及其所有用户
yao run models.supplier.Find 1 '::{"withs":{ "users": {} }}'

# 查询所有供应商及其所有用户
yao run models.supplier.Get '::{"withs":{ "users": {} }}'

指定关联字段

bash
# 仅查询用户的name字段
yao run models.supplier.Find 1 '::{"withs":{ "users": { "query":{"select":["name"] }} }}'

关联数据筛选

bash
# 查询名为"张无忌"的用户所属的供应商
yao run models.supplier.Find 1 '::{"withs":{ "users": { "wheres":[{"column":"name", "value":"张无忌"}] } }}'

嵌套关联查询

关联关系支持嵌套查询,可以通过多层 withs 参数实现。

多层嵌套示例

bash
# 查询供应商及其用户,同时查询用户的供应商信息(形成循环引用)
yao run models.supplier.Find 1 '::{"withs":{ "users": { "withs": {"supplier":{} } } }}'

# 查询所有供应商的嵌套数据
yao run models.supplier.Get '::{"withs":{ "users": { "withs": {"supplier":{} } } }}'

注意事项

  1. 嵌套查询可能导致数据量过大,请谨慎使用深层嵌套
  2. 关联查询会增加数据库负担,请只查询必要字段
  3. 复杂的关联查询建议在后端处理而非直接通过API查询

通过合理使用数据模型关联,可以大幅简化数据查询逻辑,提高开发效率。