将SQLite数据映射到TypeScript对象:异步处理与类型安全实践


将SQLite数据映射到TypeScript对象:异步处理与类型安全实践

在使用electron的`sqlite3`库时,将从sqlite数据库读取的原始行数据反序列化为强类型的typescript类是一个常见挑战。本文将详细介绍如何通过结合promise处理异步数据库操作、正确迭代查询结果以及利用typescript的类型断言,安全有效地将sqlite数据映射到预定义的typescript对象结构,从而提升代码的可读性和类型安全性。

1. 理解数据库操作的异步性

在使用Node.js环境下的数据库库(如sqlite3)时,一个核心概念是大多数数据库操作都是异步的。这意味着当你执行一个查询时,程序不会等待查询结果返回才继续执行后续代码。sqlite3库的all()方法尤其如此,它不直接返回查询结果,而是通过回调函数来提供结果。

原始代码中尝试直接从query.all()的返回值中获取数据并进行同步处理,这与sqlite3库的设计不符。query.all()方法实际上返回的是Statement对象本身,用于链式调用,而非查询结果。查询结果会在其提供的回调函数中返回。

2. 使用Promise封装异步操作

为了更好地管理异步操作并使其代码更具可读性和可维护性,推荐使用Promise来封装数据库操作。这样,调用者可以通过async/await语法来等待数据库操作完成并获取结果。

以下是如何将GetAllObjs函数改造为返回Promise的示例:

MarketingBlocks AI MarketingBlocks AI

AI营销助理,快速创建所有的营销物料。

MarketingBlocks AI 27 查看详情 MarketingBlocks AI
import * as sqlite3 from 'sqlite3'; // 假设 db 实例来自这里
// 假设 Obj 类已定义
interface Obj {
  id: number;
  name: string;
  amount: number;
}

// 示例数据库实例(实际应用中应妥善初始化)
const db = new sqlite3.Database(':memory:'); 

// 示例表创建函数(为演示目的,实际应用中可能在应用启动时执行)
export const CreateObjTable = (): Promise<sqlite3.RunResult> => {
  return new Promise((resolve, reject) => {
    db.run(`
      CREATE TABLE IF NOT EXISTS ObjTable
      (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT,
        amount INTEGER
      )
    `, function(err) {
      if (err) {
        reject(err);
      } else {
        resolve(this); // 'this' 包含 lastID 和 changes
      }
    });
  });
};

// 示例数据插入(为演示目的)
export const InsertObj = (name: string, amount: number): Promise<sqlite3.RunResult> => {
  return new Promise((resolve, reject) => {
    db.run(`INSERT INTO ObjTable (name, amount) VALUES (?, ?)`, [name, amount], function(err) {
      if (err) {
        reject(err);
      } else {
        resolve(this);
      }
    });
  });
};

export const GetAllObjs = (): Promise<Obj[]> => {
    const query = db.prepare("SELECT * FROM ObjTable");

    return new Promise((resolve, reject) => {
        let objs: Obj[] = []; // 明确类型为 Obj[]

        // query.all() 方法接受一个回调函数,其中包含错误和行数据
        query.all((err, rows: any[]) => { // rows 参数的类型为 any[]
            if (err) {
                // 如果发生错误,拒绝Promise
                return reject(err);
            }

            // 正确地迭代数组元素
            for (const row of rows) { // 使用 for...of 迭代数组的元素
                objs.push(
                    {
                        // 直接通过属性名访问列值
                        id: row.id,
                        name: row.name,
                        amount: row.amount,
                    } as Obj // 使用类型断言确保对象的类型
                );
            }
            // 成功时,解决Promise并返回结果
            resolve(objs);
        });
    });
};

代码解析:

  • new Promise((resolve, reject) => { ... }): 创建一个新的Promise,它接受一个执行器函数,该函数有两个参数:resolve(当异步操作成功时调用)和reject(当异步操作失败时调用)。
  • query.all((err, rows: any[]) => { ... }): 这是sqlite3库提供的all()方法的标准回调签名。err参数用于捕获可能发生的数据库错误,rows参数则是一个包含所有查询结果行的数组。
  • 错误处理: 在回调函数内部,首先检查err是否存在。如果存在,调用reject(err)来表示Promise失败。
  • for (const row of rows): 这是J*aScript/TypeScript中迭代数组元素的正确方式。与for...in(迭代对象的键或数组的索引)不同,for...of直接迭代数组的每个元素(即每一行数据对象)。
  • row.id, row.name, row.amount: sqlite3查询返回的行对象通常会将其列名作为属性。因此,可以直接通过row.columnName的方式访问每个列的值。
  • {} as Obj: 尽管TypeScript在运行时会被编译为J*aScript,但使用类型断言as Obj可以帮助TypeScript编译器在开发阶段进行类型检查,确保你创建的对象符合Obj接口的结构。
  • resolve(objs): 当所有行都被处理并映射到Obj数组后,调用resolve(objs)来完成Promise,并将objs数组作为其结果返回。

3. 示例用法

现在,你可以使用async/await语法来调用GetAllObjs函数,使其代码看起来更像同步代码:

// 假设 db 已经连接
// db = new sqlite3.Database('your_database.db');

async function main() {
  try {
    // 确保表已创建
    await CreateObjTable();
    console.log("ObjTable created.");

    // 插入一些示例数据
    await InsertObj('Item A', 100);
    await InsertObj('Item B', 250);
    console.log("Sample data inserted.");

    // 获取所有对象
    const allObjs = await GetAllObjs();
    console.log("Fetched objects:", allObjs);

    // 预期输出:
    // Fetched objects: [
    //   { id: 1, name: 'Item A', amount: 100 },
    //   { id: 2, name: 'Item B', amount: 250 }
    // ]

  } catch (error) {
    console.error("An error occurred:", error);
  } finally {
    // 确保在应用退出时关闭数据库连接
    // db.close(); 
  }
}

main();

4. 注意事项与最佳实践

  • 错误处理: 始终在Promise的reject分支中处理数据库操作可能出现的错误。
  • 数据库连接管理: 确保数据库连接在应用程序生命周期中得到妥善的打开和关闭。在Electron主进程中,通常在应用启动时打开,在应用关闭时关闭。
  • 类型定义: 为你的数据库表结构定义清晰的TypeScript接口或类,这有助于提升代码的可读性和可维护性。
  • SQL注入: 在构建SQL查询时,如果涉及用户输入,请务必使用参数化查询(如db.run('INSERT INTO ... VALUES (?, ?)', [value1, value2]))来防止SQL注入攻击。
  • ORM工具: 对于更复杂的数据库交互和对象映射需求,可以考虑使用Object-Relational Mapping (ORM) 工具,如TypeORM或Sequelize。它们提供了更高级的抽象,可以自动化大部分数据到对象的映射工作。
  • for...in vs for...of: 再次强调,for...in用于迭代对象的属性名(或数组的索引),而for...of用于迭代可迭代对象(如数组)的元素值。在处理数组时,几乎总是应该使用for...of。

总结

通过将sqlite3的异步回调方法封装在Promise中,并结合正确的数组迭代方式(for...of)和TypeScript的类型断言,我们可以优雅且类型安全地将SQLite数据库的原始行数据反序列化为预定义的TypeScript类或接口对象。这种方法不仅解决了异步处理的挑战,还大大提高了代码的健壮性和可维护性。

以上就是将SQLite数据映射到TypeScript对象:异步处理与类型安全实践的详细内容,更多请关注其它相关文章!


# java  # js  # node.js  # node  # javascript  # 链式  # 启东网站推广好不好  # 源代码  # 启动时  # 殷都区网站seo营销怎么收费  # 河池机械网站建设  # 九五策划高端网站建设  # 新乡seo推广公司电话  # yoast seo premium破解版  # 灵石网站推广厂家电话  # 男潮服关键词排名查询  # 专业外国网站建设  # 微信网站建设优化企业  # 使其  # 行数  # 有什么  # 这是  # 查询结果  # 迭代  # 回调  # sq  # ai  # 工具  # 回调函数  # app  # typescript 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 企查查官网和爱企查 企查查企业查询官网入口  抖音团长模式怎么做?团长模式是什么意思?  B站怎么开|直播| B站|直播|申请需要什么条件【新手必看】  Win10如何彻底关闭OneDrive Win10禁用云同步功能【纯净】  VBA Outlook邮件自动化:高效集成Excel数据与列标题的策略  windows server2019显卡驱动怎么安装_winserver2019显卡驱动安装与远程桌面优化  Highcharts雷达图径向轴数值标签实现教程  Google Cloud Functions 时区处理指南:理解与最佳实践  猫眼app抢票快还是小程序快  windows10怎么设置电源按钮_windows10按下电源键功能修改  空腹吃苹果好吗 苹果空腹摄入指南  《火花chat》搜索好友方法  鸿蒙单条备忘录如何加密  在J*a中如何实现类的继承与方法重用_OOP继承方法重用技巧分享  Google Drive API 认证:服务账户与OAuth 2.0的选择与实践  《爱笔思画x》涂色教程  大众点评了却看不到是怎么回事  优化响应式标题底部边框:CSS实现技巧与最佳实践  Google Drive API服务器端访问指南:服务账户认证详解  火狐浏览器如何刷新修复浏览器 火狐浏览器“重置Firefox”功能详解  《理想汽车》权限管理设置方法  人教版电子教材在线获取指南  mysql怎么查询数据_mysql基础查询语句使用教程  汽水音乐官方网站登录入口_汽水音乐网页版进入链接  C++如何将字符串转换为大写或小写_C++ transform函数的使用技巧  小米civi如何设置锁屏时间  优化 React onClick 事件处理:函数引用与箭头函数的对比  吃完饭就犯困是什么原因 餐后嗜睡如何缓解  Coolpad5890 ROM刷机包  优化Flask模板中SQLAlchemy查询迭代标签:处理字符串空格问题  J*aScript大数运算_BigInt使用指南  qq音乐官方网站入口_qq音乐在线听歌网页版链接  iPhone 14 Pro如何更改区域设置_iPhone 14 Pro地区语言修改教程  抖音火山版注销账号抖音会注销吗 抖音火山版与抖音账号注销关系  网页版网易云音乐入口_网易云音乐在线官网登录  获取WooCommerce产品在后台编辑页面的分类ID  《暗黑破坏神4》国服回归送狂欢礼包 价值6916元  《微信》视频号原创声明开启方法  行者app怎样导出日志  Leaflet地图弹出窗口图片动态显示:避免缺失图标的专业指南  《异星探险家》古怪的物品作用介绍  J*a中为什么强调组合优于继承_组合模式带来的灵活性与可维护性解析  uc浏览器官网网页版使用 uc浏览器官网免费在线首页  C++怎么解决数值计算中的精度问题_C++浮点数误差与数值稳定性分析  秋风萧瑟洪波涌起中的萧瑟指的是什么  word怎么将图片设置为页面背景并不影响打印_Word图片背景设置方法  XPath动态元素定位:如何精准选择文本内容变化的元素  如何用mysql实现客户反馈管理_mysql客户反馈数据库方法  键盘声音异常怎么回事_键盘异响怎么处理  苹果电脑如何快速截图并编辑 苹果电脑截屏标注快捷操作 

 2025-11-14

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.