Skip to content

暴露只读视图

视图是数据库中的预定义查询,对外表现为一张虚拟表。当需要对外提供只读的复杂查询结果(多表 JOIN、聚合、数据脱敏)时,视图比直接暴露表更安全、更可控。本教程带你完成从创建视图到发布 API 的完整流程。

场景

图书管理系统需要提供一个只读接口,返回每本书的详细信息,包括书名、作者名、分类名和出版社——这些数据分散在四张表中。直接暴露表意味着消费者需要自己做四次查询和关联。我们用一个视图来封装这个查询。

第一步:创建视图

在数据库中创建视图,将需要的字段 JOIN 在一起:

sql
CREATE VIEW dbo.vw_Books_Details AS
SELECT
    b.id,
    b.title,
    b.[year],
    b.pages,
    a.name AS author_name,
    c.name AS category_name,
    p.name AS publisher_name
FROM dbo.Books b
    LEFT JOIN dbo.Authors a ON b.author_id = a.id
    LEFT JOIN dbo.Categories c ON b.category_id = c.id
    LEFT JOIN dbo.Publishers p ON b.publisher_id = p.id;

视图已经包含了业务需要的全部字段。现在把它暴露为 API。

第二步:添加视图实体

bash
dab add BookDetail \
  --source "dbo.vw_Books_Details" \
  --source.type "view" \
  --fields.name "id" \
  --fields.primary-key "true" \
  --permissions "anonymous:read"

关键点:

  • --source.type "view":声明这是一个视图,不是表。
  • --fields.primary-key "true":视图书没有物理主键,必须手动指定。

生成的配置:

json
{
  "BookDetail": {
    "source": {
      "type": "view",
      "object": "dbo.vw_Books_Details"
    },
    "fields": [
      { "name": "id", "primary-key": true }
    ],
    "permissions": [
      { "role": "anonymous", "actions": ["read"] }
    ]
  }
}

WARNING

如果不指定 primary-key,按主键查询(GET /api/BookDetail/id/1)会退化为列表查询并返回空数组。视图没有物理主键,引擎无法自动推断。

第三步:仅授予只读权限

视图书是只读的(包含多表 JOIN),只需授予 read 权限:

json
{
  "permissions": [
    { "role": "anonymous", "actions": ["read"] }
  ]
}

不要给视图配置 createupdatedelete 权限——即使配置了,大多数多表 JOIN 视图也是不可更新的,数据库会拒绝写操作。

第四步:启动并测试

bash
dab start

查询全部

bash
curl http://localhost:5000/api/BookDetail
json
{
  "value": [
    {
      "id": 1000,
      "title": "深入浅出 SQL Server",
      "year": 2020,
      "pages": 326,
      "author_name": "张三",
      "category_name": "数据库",
      "publisher_name": "科技出版社"
    }
  ]
}

按主键查询

bash
curl http://localhost:5000/api/BookDetail/id/1000

筛选和排序

bash
# 某个分类下的书,按年份降序
curl "http://localhost:5000/api/BookDetail?\$filter=category_name%20eq%20%27数据库%27&\$orderby=year%20desc"

# 只返回标题和作者
curl "http://localhost:5000/api/BookDetail?\$select=title,author_name"

GraphQL 查询

graphql
{
  bookDetails(
    filter: { category_name: { eq: "数据库" } }
    orderBy: { year: DESC }
  ) {
    items { title author_name year pages }
  }
}

视图 vs 直接暴露表

维度视图直接暴露表
数据来源可跨多表 JOIN单表
字段控制视图定义时就限定通过 fields.exclude 排除
业务逻辑在 SQL 中封装
只读安全SQL 层面不可更新需要权限配置控制
维护改 SQL 即可,无需改 DAB 配置需同时改配置

对于以下场景,优先用视图:

  • 跨多表的数据查询需要对外提供。
  • 需要对原始数据做计算、聚合或脱敏。
  • 不希望消费者接触到原始表结构。
  • 只读数据查询,不需要写操作。

限制

  • 视图不支持 relationships 配置(不能在视图上定义 GraphQL 关系查询)。
  • 存储过程不能作为视图的替代——视图支持筛选、排序、分页,存储过程不支持。
  • 如果视图可更新(基于单表的简单视图),可以授予写权限,但需要逐一验证数据库是否允许更新操作。

下一步

数据墙DBW 产品文档与开发指南。