数据模型——饮食记录

news2024/10/23 2:40:51

数据模型——饮食记录

本次实验完成饮食记录的数据模型,如下图所示

在这里插入图片描述

该饮食记录模型与上次的记录项数据模式定义处理方式相同,我们首先分析其数据结构,我们发现首先有早餐、午餐、晚餐等记录类型数据模型,其包括了id、类型名称、类型图标、类型推荐最小和最大卡路里等。在每个类型中又可以添加记录项,记录项也有id、类型id、卡路里总数、和上节课定义的记录项相同的数据项和食品数量或运动时长等组成的记录项数据模型。

记录类型数据模型

export default class RecordType{
  /**
   * 类型id
   */
  id: number
  /**
   * 类型名称
   */
  name: ResourceStr
  /**
   * 类型图标
   */
  icon: ResourceStr
  /**
   * 类型推荐最小卡路里
   */
  min: number
  /**
   * 类型推荐最大卡路里
   */
  max: number

  constructor(id: number, name: ResourceStr, icon: ResourceStr, min: number = 0, max: number = 0) {
    this.id = id
    this.name = name
    this.icon = icon
    this.min = min
    this.max = max
  }
}

可以看出min和max设置了默认可选值,因为当类型为运动时,没有类型推荐最小卡路里、类型推荐最大卡路里

import RecordType from '../viewmodel/RecordType'

enum RecordTypeEnum {
  /**
   * 早餐
   */
  BREAKFAST,
  /**
   * 午餐
   */
  LUNCH,
  /**
   * 晚餐
   */
  DINNER,
  /**
   * 加餐
   */
  EXTRA_MEAL,
  /**
   * 运动
   */
  WORKOUT
}

/**
 * 记录类型常量
 */
const RecordTypes: RecordType[] = [
  new RecordType(0, $r("app.string.breakfast"), $r("app.media.ic_breakfast"), 423, 592),
  new RecordType(1, $r("app.string.lunch"), $r("app.media.ic_lunch"), 592, 761),
  new RecordType(2, $r("app.string.dinner"), $r("app.media.ic_dinner"), 423, 592),
  new RecordType(3, $r("app.string.extra_meal"), $r("app.media.ic_extra_m"), 0, 169),
  new RecordType(4, $r("app.string.workout"), $r("app.media.ic_workout")),
]

export {RecordTypes, RecordTypeEnum}

这里设置RecordTypeEnum枚举的作用与上次相同,有助于每一项数据项能方便的找到其所在的类型。

记录项数据模型

import RecordItem from './RecordItem'

/**
 * 饮食记录的页面数据模型
 */
export default class RecordVO {
  /**
   * 记录id
   */
  id: number
  /**
   * 饮食记录类型
   */
  typeId: number

  /**
   * 卡路里总数
   */
  calorie: number

  /**
   * 记录中的食物或运动信息
   */
  recordItem: RecordItem

  /**
   * 食物数量或运动时长,如果是运动信息则无
   */
  amount: number = 0
}

在其中recordItem的类型是上次我们定义的RecordItem数据模型,方便我们直接使用上次定义的数据模型中的数据。

在这里插入图片描述

如图所示,RecordModel我们采用了关系型数据库来保存记录项的数据,通过关系型数据库来进行数据操作,这样做的原因是因为,这部分数据是可以根据日期进行查询的,还可以执行删除操作,所以不能像其他数据一样保存在内存中,必须保存在关系型数据库中才能进行

持久化保存。

为了操作数据库方便,我们定义了数据库通用工具类

import common from '@ohos.app.ability.common';
import relationalStore from '@ohos.data.relationalStore';
import { ColumnInfo, ColumnType } from '../bean/ColumnInfo';
import Logger from './Logger';

const DB_FILENAME: string = 'HeiMaHealthy.db'

class DbUtil {
  rdbStore: relationalStore.RdbStore

  initDB(context: common.UIAbilityContext): Promise<void> {
    let config: relationalStore.StoreConfig = {
      name: DB_FILENAME,
      securityLevel: relationalStore.SecurityLevel.S1
    }
    return new Promise<void>((resolve, reject) => {
      relationalStore.getRdbStore(context, config)
        .then(rdbStore => {
          this.rdbStore = rdbStore
          Logger.debug('rdbStore 初始化完成!')
          resolve()
        })
        .catch(reason => {
          Logger.debug('rdbStore 初始化异常', JSON.stringify(reason))
          reject(reason)
        })
    })
  }

  createTable(createSQL: string): Promise<void> {
    return new Promise((resolve, reject) => {
      this.rdbStore.executeSql(createSQL)
        .then(() => {
          Logger.debug('创建表成功', createSQL)
          resolve()
        })
        .catch(err => {
          Logger.error('创建表失败,' + err.message, JSON.stringify(err))
          reject(err)
        })
    })
  }
//添加通用新增方法
 insert(tableName:string,obj:any,columns:ColumnInfo[]){
  return new Promise((resolve,reject)=>{
    //1.构建新增的数据
    let value=this.buildValueBucket(obj,columns)
    //2.新增
    this.rdbStore.insert(tableName,value,(err,id)=>{
      if (err) {
        Logger.debug('新增失败!',JSON.stringify(err))
        reject(err)
      }else {
        Logger.debug('新增成功!新增id:',id.toString())
        resolve(id)
      }
    })
  })
 }

//通用删除
  delete(predicates:relationalStore.RdbPredicates){
    return new Promise((resolve,reject)=>{
      //1.删除
      this.rdbStore.delete(predicates,(err,rows)=>{
        if (err) {
          Logger.debug('删除失败!',JSON.stringify(err))
          reject(err)
        }else {
          Logger.debug('删除成功!删除行数:',rows.toString())
          resolve(rows)
        }
      })
    })
  }

//批量查询
  queryForList<T>(predicates:relationalStore.RdbPredicates,columns:ColumnInfo[]):Promise<T[]>{
    return new Promise((resolve,reject)=>{
      //1.删除
      this.rdbStore.query(predicates,columns.map(info=>info.columnName),(err,result)=>{
        if (err) {
          Logger.debug('查询失败!',JSON.stringify(err))
          reject(err)
        }else {
          Logger.debug('查询成功!查询行数:',result.rowCount.toString())
          resolve(this.parseResultSet(result,columns))
        }
      })
    })
  }

  //解析resultSET
  parseResultSet<T>(result:relationalStore.ResultSet,columns:ColumnInfo[]):T[]{
   //1.声明最终返回结果
    let arr=[]
  //2.判断是否有结果
    if (result.rowCount<=0) {
     return arr;
    }
    //3.处理结果
    while (!result.isAtLastRow) {
      //3.1 去下一行
      result.goToNextRow()
      //3.2 解析该行数据,转为结果对象格式
      let obj={}
      columns.forEach(info=>{
        let val=null
        switch (info.type){
          case ColumnType.LONG:
          val=result.getLong(result.getColumnIndex(info.columnName))
          break;
          case ColumnType.DOUBLE:
          val=result.getDouble(result.getColumnIndex(info.columnName))
          break;
          case ColumnType.STRING:
          val=result.getString(result.getColumnIndex(info.columnName))
          break;
          case ColumnType.BLOB:
          val=result.getBlob(result.getColumnIndex(info.columnName))
          break;
        }
        obj[info.name]=val;
      })
      //3.3 将对象填充到数组
      arr.push(obj)
    }
    return arr;
  }

buildValueBucket(obj:any,columns:ColumnInfo[]):relationalStore.ValuesBucket{
  //1.构建数据
  let value={}
  columns.forEach(info=>{
    let val=obj[info.name]
    if (typeof val !=='undefined') {
      value[info.columnName]=val
    }
  })
  return value
}

}


let dbUtil: DbUtil = new DbUtil();

export default dbUtil as DbUtil

可以看出,我们只需要提供DBUtil中所需方法的参数,即可进行增删改查操作,适用于所有数据库。但是想要实现该功能,需要在EntryAbility中初始化RDB工具和数据库中表的建立:

async  onCreate(want, launchParam) {
   //1.加载用户首选项
   PreferenceUtil.loadPreference(this.context)
   //2.初始化日期
   AppStorage.SetOrCreate(CommonConstants.RECORD_DATE,DateUtil.beginTimeOfDay(new Date()))
   //3.初始化RDB工具
  await DbUtil.initDB(this.context)
   //4.创建record表的创建
  DbUtil.createTable(RecordModel.getCreateTableSql())

   hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
 }

在完成这样后我们便可以在RecordModel中调用DBUtil所提供的方法,进行record数据表的增删改查操作,从而完成各种业务逻辑。

观察下面的代码,const CREATE_TABLE_SQL提供给了EntryAbility进行数据库中record表的建立,而且只有列名与数据库列名的映射正确,才能使自己定义的数据模型能正确使用数据库。

/**
 * 数据库建表语句
 */
import relationalStore from '@ohos.data.relationalStore'
import { ColumnInfo, ColumnType } from '../common/bean/ColumnInfo'
import RecordPO from '../common/bean/RecordPO'
import DbUtil from '../common/utils/DbUtil'
const CREATE_TABLE_SQL: string = `
 CREATE TABLE IF NOT EXISTS record (
   id INTEGER PRIMARY KEY AUTOINCREMENT,
   type_id INTEGER NOT NULL,
   item_id INTEGER NOT NULL,
   amount DOUBLE NOT NULL,
   create_time INTEGER NOT NULL
 )
 `
//列名与数据库列名的映射
const COLUMNS: ColumnInfo[] = [
  {name: 'id', columnName: 'id', type: ColumnType.LONG},
  {name: 'typeId', columnName: 'type_id', type: ColumnType.LONG},
  {name: 'itemId', columnName: 'item_id', type: ColumnType.LONG},
  {name: 'amount', columnName: 'amount', type: ColumnType.DOUBLE},
  {name: 'createTime', columnName: 'create_time', type: ColumnType.LONG}
]

const TABLE_NAME = 'record'
const ID_COLUMN = 'id'
const DATE_COLUMN = 'create_time'

class RecordModel {
  getCreateTableSql(): string {
    return CREATE_TABLE_SQL
  }
//插入
  insert(record:RecordPO){
    return DbUtil.insert(TABLE_NAME,record,COLUMNS)
  }
//删除
  deleteById(id:number){
    //1.删除条件
    let predicates=new relationalStore.RdbPredicates(TABLE_NAME)
    predicates.equalTo(ID_COLUMN,id)
    //2.删除
    return DbUtil.delete(predicates)
  }

  //查找(按日期)
  listByDate(date:number){
    //1.查询条件
    let predicates=new relationalStore.RdbPredicates(TABLE_NAME)
    predicates.equalTo(DATE_COLUMN,date)
    //2.查询
    DbUtil.queryForList(predicates,COLUMNS)
  }
}

let recordModel = new RecordModel()

export default recordModel as RecordModel

下次课我们将完成利用此数据模型,实现保存不同日期的饮食记录的数据保存功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1844323.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

处理文本内容的命令和正则表达式

处理文本内容的命令 正则表达式匹配的是文本内容&#xff0c;linux的文本三剑客 都是针对文本内容 文本三剑客&#xff1a; grep 过滤文本内容 sed 针对文本内容进行增删改查 awk 按行取列 文本三剑客都是按行进行匹配。 grep grep的作用就是使用正则表达式来匹配文本内…

档案数字化建设要点

目前&#xff0c;档案信息数字化的现状是档案标准化、规范化滞后和应用软件多乱&#xff0c;这些都严重影响了系统整体水平的提高。档案信息自动化的内涵包括档案工作的各个方面和各个环节&#xff0c;其中首要的是档案业务要规范&#xff0c;档案标准要建立健全和真正实施。档…

【Python高级编程】Pickle实现AI算法训练的权重数据的保存

任务描述 代码实现 import pickle import time import os import numpy as np# 模拟耗时的权重计算过程 def calculate_weights():print("开始计算权重...")time.sleep(5) # 模拟耗时操作&#xff0c;暂停5秒以模拟计算过程weights np.random.rand(10, 10) # 随机…

RealityCheck™电机监测和预测性维护模型

RealityCheck™电机 一个附加的软件工具箱&#xff0c;可实现条件监测和预测性维护功能&#xff0c;而无需依赖额外的传感器。相反&#xff0c;它使用来自电机控制过程的电子信息作为振动和其他传感器的代理。凭借其先进的信号处理和机器学习(ML)模型&#xff0c;RealityCheck …

[AIGC] 使用Google的Guava库中的Lists工具类:常见用法详解

在Java程序设计中&#xff0c;集合是我们最常用的数据结构之一。为了方便我们操作集合&#xff0c;Google的Guava库提供了一个名为Lists的工具类&#xff0c;它封装了许多用于操作List对象的实用方法。在本文中&#xff0c;我们将详细介绍其常见的用法&#xff0c;以帮助您更好…

S级猫主食冻干测评出来了:希喂、K9、朗诺实测分享

对于许多宠物主人来说&#xff0c;一到挑选主食冻干就头疼。尽管主食冻干为猫咪带来的益处远超过普通猫粮&#xff0c;但其价格也相对较高。因此&#xff0c;许多宠物主人担心高价购买的主食冻干营养价值并不高。实际上&#xff0c;除了营养&#xff0c;安全性和配方也是选购时…

【课程系列04】某客时间AI大模型应用开发实战营

网盘链接 https://pan.baidu.com/s/1blR1eIMDIIp6AbxU4YaK9w 课程收获 "AI大模型应用开发实战营"是一个为期八周的在线课程&#xff0c;旨在教授学员如何开发和应用AI大模型。课程内容从基础理论到实际应用&#xff0c;逐步深入&#xff0c;覆盖了以下要点&#x…

推荐一个大佬们都在用的IDE主题-Dracula Theme

Dracula主题 对于颜色的主题&#xff0c;每个人的喜欢都有所区别&#xff0c;我喜欢Dracula主题&#xff0c;基本IDE编辑器能配置的都会配置这个主题颜色。然后偶然有一天我发现这个网站&#xff1a;https://draculatheme.com/。才发现Dracula不再仅仅只是个主题了&#xff0c…

有了它,再也不用为客户管理而烦恼

在竞争激烈的市场环境中&#xff0c;有效的客户关系管理&#xff08;CRM&#xff09;系统是企业获取商机、提高成单效率的关键。搭贝CRM管理系统是基于市场业务需求量身定制的&#xff0c;通过记录客户360度画像和跟进信息&#xff0c;实现客户管理的精细化和高效流转。 &#…

Linux:文件描述符

文件描述符实际上就是一个小整数 0 & 1 & 2 Linux进程默认情况下会有3个缺省打开的文件描述符&#xff0c;分别是标准输入0&#xff0c; 标准输出1&#xff0c; 标准错误2. 0,1,2对应的物理设备一般是&#xff1a;键盘&#xff0c;显示器&#xff0c;显示器 所以输入输…

为电脑小白推荐的5款实用工具软件

​ 电脑上的各类软件有很多&#xff0c;除了那些常见的大众化软件&#xff0c;还有很多不为人知的小众软件&#xff0c;专注于实用功能&#xff0c;简洁干净、功能强悍。 1.磁盘空间分析——TreeSize Free ​ TreeSize Free是一款免费的磁盘空间分析工具&#xff0c;能够扫描…

深度学习模型训练中 学习率参数 设置大小问题及设置合适值

&#x1f4aa; 专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &#x1f4dd;《暗光增强》 &a…

对30年国债利率破2.5%的复盘反思

短期看&#xff0c;以月为维度&#xff0c;长端和超长端利率依然具有较强的向下突破的惯性&#xff1b;中期看&#xff0c;以季为维度&#xff0c;长端依然面临向下赔率不足的约束&#xff0c;但调整需要多重利空共振的契机。 短期看多&#xff0c;逢高配置”的四点逻辑 逻辑一…

SpringBoot:SpringBoot集成Druid监控慢SQL

一、前言 数据库连接池是一个至关重要的组成部分&#xff0c;一个优秀的数据库连接池可以显著提高应用程序的性能和可伸缩性。常见的连接池&#xff1a;Druid、HikariCP、C3P0、DBCP等等&#xff0c;不过目前大部分都是使用Druid或者SpringBoot默认的HikariCP&#xff01; 本文…

计算机网络 交换机的基本配置

一、理论知识 1.三种模式&#xff1a; ①用户模式&#xff1a;当登录路由器后&#xff0c;系统自动进入用户EXEC命令模式。 例如&#xff1a; Router> 在用户模式状态下&#xff0c;用户只能查看路由器的连接状态和基本信息&#xff0c;访问其他网络和主机&#xff0c…

lombok常用注解使用与原理

什么是lombok 一个优秀的Java代码库&#xff0c;简化了Java的编码&#xff0c;为Java代码的精简提供了一种方式 使用方法&#xff1a;pom文件中引入依赖 <!--scope&#xff1a;provided&#xff0c;只在编译阶段生效&#xff0c;不需要打入包中--> <dependency>…

AI 编译器技术分享会:上海交大/中科院计算所/微软亚研/智源,他们来了!

4 场 Meetup、3 个城市、19 位嘉宾、1k 行业从业者、累计 100w 曝光&#xff0c; 2023 年 AI 编译器社区小小刷新了一下存在感&#xff0c;我们在非常细分的领域里找到了最为垂直的开发者和工程师&#xff0c;从 0 到 1 建立起一个个小据点&#xff0c;搭建交流平台、促成企内合…

求最小生成树的新算法

不管 prim 算法还是 kruskal 算法都基于 “当前可见最短边” 作贪心策略&#xff0c;但这并不适合分布式并行操作&#xff0c;比方说所有节点一起构建最小生成树&#xff0c;这些算法都显得同步开销过大&#xff0c;甚至导出错误的结果。 最近研究并构建最大流多路径传输协议的…

韩顺平0基础学Java——第27天

p548-568 明天开始坦克大战 Entry 昨天没搞明白的Map、Entry、EntrySet&#xff1a;//GPT教的 Map 和 Entry 的关系 1.Map 接口&#xff1a;它定义了一些方法来操作键值对集合。常用的实现类有 HashMap、TreeMap 等。 2. Entry接口&#xff1a;Entry 是 Map 接口的一个嵌…

【高等数学】傅里叶级数

最近刷了会抖音&#xff0c;看到一个非常有趣的现象&#xff1a;傅里叶级数&#xff0c;今天挑了几个视频来供大家学习。 1.傅里叶级数概念 【小崔说数】傅里叶级数专题https://www.bilibili.com/video/BV1Uq4y1q7xk?t117.4 2.傅里叶级数动画 【谜之舒适】12分钟的傅立叶级…