WatermelonDB 数据模型(Model)深度解析

WatermelonDB 数据模型(Model)深度解析

WatermelonDB 🍉 Reactive & asynchronous database for powerful React and React Native apps ⚡️ WatermelonDB 项目地址: https://gitcode.com/gh_mirrors/wa/WatermelonDB

什么是数据模型(Model)

在 WatermelonDB 中,Model 类代表着应用程序中的一种实体类型。例如,在博客应用中常见的 Post(文章)、Comment(评论)、User(用户) 等都是典型的数据模型。每个 Model 都对应着数据库中的一个表,它定义了该类型实体的结构和行为。

创建基础模型

让我们从创建一个简单的 Post 模型开始:

// model/Post.js
import { Model } from '@nozbe/watermelondb'

export default class Post extends Model {
  static table = 'posts'
}

关键点说明:

  1. 每个 Model 必须继承自基础 Model
  2. 必须通过 static table 指定对应的表名(与之前定义的 Schema 保持一致)
  3. 创建后需要将 Model 注册到数据库实例中
// index.js
import Post from 'model/Post'

const database = new Database({
  modelClasses: [Post], // 在此处注册模型
  // ...其他配置
})

模型关联关系

现实应用中的数据很少孤立存在,模型之间通常存在各种关联关系。WatermelonDB 提供了清晰的关联定义方式。

一对多关系示例

假设一个文章(Post)可以有多条评论(Comment),每条评论属于一篇文章:

class Post extends Model {
  static table = 'posts'
  static associations = {
    comments: { type: 'has_many', foreignKey: 'post_id' },
  }
}

class Comment extends Model {
  static table = 'comments'
  static associations = {
    post: { type: 'belongs_to', key: 'post_id' },
  }
}

关键点:

  • 在"父"模型(Post)中使用 has_many 类型
  • 在"子"模型(Comment)中使用 belongs_to 类型
  • 必须使用相同的外键字段名(post_id)
  • foreignKeykey 参数实际上指向同一字段,只是命名约定不同

定义模型字段

模型字段对应数据库表中的列,使用装饰器语法定义:

import { field, text } from '@nozbe/watermelondb/decorators'

class Post extends Model {
  static table = 'posts'
  
  @text('title') title       // 文本字段,自动去除首尾空格
  @text('body') body         // 同上
  @field('is_pinned') isPinned // 普通字段
}

字段类型说明:

  • @field - 基础字段装饰器,类型与 Schema 中定义的列类型一致
  • @text - 专为用户输入的文本设计,会自动处理空格
  • 字段名使用 camelCase(JavaScript 惯例),列名使用 snake_case(数据库惯例)

日期字段处理

对于日期类型,使用专门的 @date 装饰器:

import { date } from '@nozbe/watermelondb/decorators'

class Post extends Model {
  @date('last_event_at') lastEventAt  // 返回 JavaScript Date 对象
}

计算字段

可以通过 getter 定义基于现有字段的计算属性:

class Post extends Model {
  @date('archived_at') archivedAt

  get isRecentlyArchived() {
    return this.archivedAt && 
           this.archivedAt.getTime() > Date.now() - 7 * 24 * 3600 * 1000
  }
}

高级关联定义

一对一关系

使用 @relation@immutableRelation 定义指向单个相关记录的字段:

import { relation, immutableRelation } from '@nozbe/watermelondb/decorators'

class Comment extends Model {
  @relation('posts', 'post_id') post      // 可变的关联文章
  @immutableRelation('users', 'author_id') author // 不可变的作者
}

区别:

  • @relation - 常规关联,可以修改
  • @immutableRelation - 不可变关联,创建后不能修改

一对多关系查询

使用 @children 装饰器定义获取子记录的查询:

import { children } from '@nozbe/watermelondb/decorators'

class Post extends Model {
  static associations = {
    comments: { type: 'has_many', foreignKey: 'post_id' },
  }

  @children('comments') comments  // 获取所有关联评论
}

注意:必须先定义 has_many 关联才能使用 @children

自定义查询

可以基于基础查询创建更复杂的自定义查询:

import { Q } from '@nozbe/watermelondb'

class Post extends Model {
  @children('comments') comments
  
  @lazy verifiedComments = this.comments.extend(
    Q.where('is_verified', true)  // 只获取已验证的评论
  )
}

数据操作方法

定义写入方法

使用 @writer 装饰器定义修改数据的方法:

import { writer } from '@nozbe/watermelondb/decorators'

class Comment extends Model {
  @field('is_spam') isSpam

  @writer async markAsSpam() {
    await this.update(comment => {
      comment.isSpam = true  // 标记为垃圾评论
    })
  }
}

关键点:

  • 所有修改数据的操作必须标记为 @writer
  • 使用 update 方法进行记录更新

高级字段特性

WatermelonDB 还提供了一些高级字段装饰器:

  • @json - 处理复杂 JSON 数据
  • @readonly - 创建只读字段
  • @nochange - 字段创建后不可修改
  • 使用 RxJS 创建可观察的复合属性

最佳实践建议

  1. 命名一致性:保持模型类名(大驼峰)与表名(蛇形)的明确对应关系
  2. 关联清晰:明确定义双向关联,保持外键一致
  3. 类型匹配:确保装饰器类型与 Schema 中定义的列类型匹配
  4. 业务封装:将常用数据操作封装为模型方法
  5. 性能考虑:对于复杂查询,考虑添加适当索引

通过合理设计数据模型,可以构建出结构清晰、易于维护的应用程序数据层。WatermelonDB 的 Model 系统提供了强大的工具来定义数据结构和关系,同时保持了良好的开发体验。

WatermelonDB 🍉 Reactive & asynchronous database for powerful React and React Native apps ⚡️ WatermelonDB 项目地址: https://gitcode.com/gh_mirrors/wa/WatermelonDB

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛曦旖Francesca

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值