新闻中心
在TypeScript中将SQLite查询结果映射到类型化对象

本教程旨在解决在electron或node.js环境中使用`sqlite3`时,如何将异步sqlite查询结果正确地反序列化并映射到typescript强类型对象的问题。文章将详细解释`sqlite3.all()`方法的异步特性,演示如何利用promise封装回调,并指导开发者使用`for...of`循环安全高效地将数据库行数据转换为自定义的typescript类实例,从而提升代码的类型安全性和可维护性。
引言:SQLite查询结果到TypeScript对象的挑战
在基于Node.js或Electron的应用程序中,使用sqlite3库与SQLite数据库交互是常见的需求。当从数据库中查询数据时,通常会得到一个原始的数据行数组。然而,为了更好地利用TypeScript的类型系统,并提高代码的可读性和健壮性,我们通常希望将这些原始数据行转换为预定义的TypeScript类或接口的实例。
直接将数据库查询结果映射到TypeScript对象可能会遇到一些挑战,特别是涉及到sqlite3库的异步操作方式以及J*aScript中循环迭代的细微差别。本教程将深入探讨这些问题,并提供一个清晰、专业的解决方案。
理解sqlite3.all()的异步特性
sqlite3库中的大多数数据库操作都是异步的,这意味着它们不会立即返回结果。db.prepare().all()方法也不例外。根据node-sqlite3的API文档,all()方法接受一个回调函数作为参数,当查询完成并获取所有结果行时,该回调函数会被调用。all()方法本身返回的是Statement对象,用于方法链式调用,而不是查询结果本身。
这意味着,如果你尝试像同步代码那样直接在query.all()之后访问结果,你将无法获取到数据,因为数据仍在异步处理中。为了正确处理这种异步行为,我们需要采用适当的异步编程模式,例如回调函数或Promise。
使用Promise封装异步操作
在现代J*aScript和TypeScript开发中,Promise是处理异步操作的首选方式,它能使异步代码的结构更清晰,避免“回调地狱”。我们可以将query.all()的基于回调的API封装在一个Promise中,使其返回一个Promise对象,这样我们就可以使用.then()或async/await来处理结果。
以下是封装GetAllObjs函数以返回一个Promise的示例:
import * as sqlite3 from 'sqlite3'; // 假设你已经配置了sqlite3
// 定义Obj接口,与数据库表结构匹配
interface Obj {
id: number;
name: string;
amount: number;
}
// 假设db是一个已连接的sqlite3数据库实例
// const db = new sqlite3.Database(':memory:');
/**
* 从ObjTable中获取所有对象并返回一个Promise
* 该Promise解析为一个Obj数组
*/
export const GetAllObjs = (): Promise<Obj[]> => {
const query = db.prepare("SELECT * FROM ObjTable");
return new Promise((resolve, reject) => {
query.all((err: Error | null, rows: any[]) => {
if (err) {
// 如果发生错误,拒绝Promise
return reject(err);
}
const objs: Obj[] = [];
// 使用 for...of 循环正确迭代行数据
for (const row of rows) {
// 将每一行数据映射到Obj接口
objs.push({
id: row.id,
name: row.name,
amount: row.amount,
});
}
// 解析Promise,返回Obj数组
resolve(objs);
});
});
};正确迭代查询结果并构建TypeScript对象
在上述Promise封装中,一个关键的改进是使用了for (const row of rows)循环来迭代查询结果。
Tanka
具备AI长期记忆的下一代团队协作沟通工具
146
查看详情
避免for...in的陷阱: 原始问题中可能出现的错误是使用for (const row in rows as Obj[])。for...in循环设计用于遍历对象的可枚举属性名称(键),而不是数组的元素值。对于数组,for...in会遍历其索引(如"0", "1", "2"等字符串),而不是数组中实际的对象。因此,row变量将是一个字符串索引,而非数据库行对象,导致row.id等访问失败。
使用for...of进行迭代:for...of循环是ES6引入的,专门用于遍历可迭代对象(如数组、Map、Set等)的元素值。当对rows数组使用for...of时,每次迭代的row变量将直接是数组中的一个数据行对象。这样,你就可以安全地通过row.columnName的方式访问每个列的值,并将其赋值给TypeScript对象的相应属性。
在回调函数内部,rows参数是一个any[]类型的数组,其中每个元素都是一个表示数据库行的J*aScript对象。这些对象的属性名与数据库表的列名相匹配。因此,我们可以直接通过row.id、row.name、row.amount等方式访问这些值,并构造新的Obj实例。
完整示例代码
为了提供更完整的上下文,以下是一个包含Obj接口定义、表创建和数据获取的综合示例:
import * as sqlite3 from 'sqlite3';
// 假设db是一个已连接的sqlite3数据库实例
// 通常在Electron主进程或Node.js服务启动时初始化
const db = new sqlite3.Database('./mydb.sqlite', (err) => {
if (err) {
console.error("Error opening database", err);
} else {
console.log("Database connected.");
}
});
// 1. 定义Obj接口,与数据库表结构匹配
interface Obj {
id: number;
name: string;
amount: number;
}
// 2. 表创建函数
export const CreateObjTable = (): Promise<sqlite3.RunResult> => {
return new Promise((resolve, reject) => {
const query = db.prepare(`
CREATE TABLE IF NOT EXISTS ObjTable
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
amount INTEGER
)
`);
query.run((err: Error | null, result: sqlite3.RunResult) => {
if (err) {
return reject(err);
}
resolve(result);
});
});
};
// 3. 插入数据示例(可选,用于测试)
export const InsertObj = (name: string, amount: number): Promise<sqlite3.RunResult> => {
return new Promise((resolve, reject) => {
const query = db.prepare("INSER
T INTO ObjTable (name, amount) VALUES (?, ?)");
query.run(name, amount, function(err: Error | null) {
if (err) {
return reject(err);
}
// this.lastID 可以获取插入的ID
resolve(this);
});
});
};
// 4. 获取所有对象并反序列化为Obj[]
export const GetAllObjs = (): Promise<Obj[]> => {
const query = db.prepare("SELECT * FROM ObjTable");
return new Promise((resolve, reject) => {
query.all((err: Error | null, rows: any[]) => {
if (err) {
return reject(err);
}
const objs: Obj[] = [];
for (const row of rows) { // 正确使用 for...of 迭代
objs.push({
id: row.id,
name: row.name,
amount: row.amount,
});
}
resolve(objs);
});
});
};
// 使用示例 (在async函数中或Promise链中调用)
(async () => {
try {
await CreateObjTable();
console.log("ObjTable created or already exists.");
await InsertObj("Item A", 100);
await InsertObj("Item B", 250);
console.log("Sample data inserted.");
const allObjs = await GetAllObjs();
console.log("Retrieved objects:", allObjs);
// 确保关闭数据库连接
db.close((err) => {
if (err) {
console.error("Error closing database", err);
} else {
console.log("Database closed.");
}
});
} catch (error) {
console.error("An error occurred:", error);
}
})();注意事项与最佳实践
- 错误处理: 在Promise中,务必在回调函数内部检查err参数。如果存在错误,应调用reject(err)来拒绝Promise,以便上层调用者能够捕获并处理错误。
- 类型断言: 在query.all()的回调中,rows通常被推断为any[]。在构建objs数组时,虽然我们知道row的结构,但为了更严格的类型检查,可以使用as Obj进行类型断言,例如objs.push(row as Obj),但这要求row的类型与Obj完全兼容。在上面的例子中,我们显式地创建了一个新对象,这提供了更好的控制和清晰度。
-
async/await: 一旦你的函数返回Promise,你就可以在调用端使用async/await语法来进一步简化异步代码的编写和阅读,使其看起来更像同步代码。
async function processData() { try { const objs = await GetAllObjs(); console.log(objs); } catch (error) { console.error("Failed to get objects:", error); } } processData(); - 数据库连接管理: 确保在应用程序生命周期的适当时候打开和关闭数据库连接,以避免资源泄露。在Electron应用中,这通常在主进程启动时打开,在应用关闭前关闭。
- 参数化查询: 在插入或更新数据时,始终使用参数化查询(如INSERT INTO ... VALUES (?, ?))来防止SQL注入攻击。
总结
通过本教程,我们学习了如何在TypeScript中优雅地处理sqlite3的异步查询结果,并将其反序列化为强类型对象。关键在于:
- 理解sqlite3.all()的异步回调机制。
- 使用Promise封装异步操作,以获得更清晰、可维护的代码结构。
- 利用for...of循环正确迭代数据库查询结果数组。
- 将每一行数据安全地映射到预定义的TypeScript接口或类实例。
遵循这些实践,将大大提高你在Electron或Node.js项目中与SQLite数据库交互时的代码质量、类型安全性和开发效率。
以上就是在TypeScript中将SQLite查询结果映射到类型化对象的详细内容,更多请关注其它相关文章!
# 都是
# 软文推广营销的方式
# 盐田谢岗网站建设
# 纺织关键词排名服务
# seo虚拟点击公司
# 驻马店营销网站推广
# 广州海珠滚屏网站建设
# 营销推广软件设计
# 青海seo服务公司
# SEO网课哪种好
# 安徽抖音营销推广方法
# 使其
# 行数
# 而不是
# 遍历
# javascript
# 如何实现
# 是一个
# 迭代
# 查询结果
# 回调
# sql注入
# ai
# 回调函数
# typescript
# node
# node.js
# js
# java
# es6
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
CSS图片焦点样式实现教程:理解与应用tabindex属性
Yandex搜索引擎官网入口_俄罗斯Yandex免登录一键直达
b站怎么删除评论_b站评论管理与删除操作
理解J*aScript Promise的微任务队列与执行顺序
mysql如何设置表访问权限_mysql表访问权限配置
msn官网入口地址手机版 msn官方网站手机最新链接
一加 Nord 5 隐私权限异常_一加 Nord 5 系统安全优化
如何为你的Composer包编写自动化测试_集成PHPUnit到Composer的scripts工作流
深入理解rpy2中的类型转换:优化Python对象到R矩阵的映射
QQ邮箱稳定登录入口_QQ邮箱官方网站网页版使用
蛙漫官方正版入口 蛙漫网页在线全集免费观看
LINUX怎么设置定时任务_LINUX crontab配置教程
cad怎么合并重叠的线段_cad清理重复重叠线条的操作方法
夸克浏览器网页版最新地址 夸克浏览器官方入口合集
顺丰快递查询系统 官方正版查询入口
魅族17怎样用浏览器译外语网页_iPhone魅族17浏览器译外语网页【即时翻译】
LINUX的perf命令入门_LINUX官方性能分析工具的使用与解读
魅族20怎样在浏览器开无图省流_iPhone魅族20浏览器开无图省流【流量节省】
C++20的source_location是什么_C++在编译期获取源码位置信息用于日志和断言
J*a应用程序首次运行自动创建文件与目录的最佳实践
UE5.7引擎表现爆炸优化无敌!5090跑4K稳定60FPS
Win11怎么设置鼠标指针速度_Win11提高鼠标指针精确度选项
铃兰之剑为这和平的世界希里技能组及加点推荐
如何使用CaptainHook和Composer管理Git钩子_在提交前自动运行代码检查的Composer配置
Win11 BitLocker密码忘了怎么办 Win11找回BitLocker恢复密钥方法【解决】
谷歌浏览器怎么给标签页静音_Chrome标签静音快捷操作
Mac终端命令大全_Mac常用Terminal指令速查
Golang如何实现容器化日志收集与分析_Golang容器日志收集分析方法
在Typer应用中优雅地处理和重组任意命令行参数
冬*霸灯泡不亮怎么办_浴霸取暖灯一盏不亮的灯座清洁修复法
构建轻量级网站内部消息系统:Formspree 集成指南
Golang并发任务中错误如何聚合_Golang goroutine error收集方式
铁路12306官网网页端快速入口 铁路12306官方首页登录教程
在J*a中如何使用Stream.map转换元素_Stream映射操作解析
KFC套餐升级怎么获取优惠代码_KFC套餐升级活动与优惠代码获取方法
解决Python单元测试中Mock异常方法调用计数为零的问题
机构:以往存储涨价周期小米利润率实际上有所改善 能转嫁给消费者等
如何将HTML表格多行数据保存到Google Sheet
Win11如何使用Windows Sandbox Win11沙盒功能开启与使用教程【详解】
mysql通配符支持数字匹配吗_mysql通配符能否用于数字匹配的解析
AO3镜像入口大全 AO3网页版内容访问全集
聚水潭ERP登录页面入口 聚水潭ERP官网登录界面
服务端验证_j*ascript输入检查
Node.js中HTML按钮与J*aScript函数交互的正确姿势
sublime怎么覆盖插件的默认快捷键_sublime快捷键优先级与设置
汽车之家官方网站官网入口_汽车之家网页版直接进入
Golang如何实现Web接口签名验证_Golang Web接口签名校验开发方法
《北京人工智能产业白皮书(2025)》发布:全年核心产值预计突破 4500 亿元
Composer如何解决json扩展缺失的错误
蛙漫2台版漫画地址 Manwa2正版网页版链接


2025-11-14
浏览次数:次
返回列表
T INTO ObjTable (name, amount) VALUES (?, ?)");
query.run(name, amount, function(err: Error | null) {
if (err) {
return reject(err);
}
// this.lastID 可以获取插入的ID
resolve(this);
});
});
};
// 4. 获取所有对象并反序列化为Obj[]
export const GetAllObjs = (): Promise<Obj[]> => {
const query = db.prepare("SELECT * FROM ObjTable");
return new Promise((resolve, reject) => {
query.all((err: Error | null, rows: any[]) => {
if (err) {
return reject(err);
}
const objs: Obj[] = [];
for (const row of rows) { // 正确使用 for...of 迭代
objs.push({
id: row.id,
name: row.name,
amount: row.amount,
});
}
resolve(objs);
});
});
};
// 使用示例 (在async函数中或Promise链中调用)
(async () => {
try {
await CreateObjTable();
console.log("ObjTable created or already exists.");
await InsertObj("Item A", 100);
await InsertObj("Item B", 250);
console.log("Sample data inserted.");
const allObjs = await GetAllObjs();
console.log("Retrieved objects:", allObjs);
// 确保关闭数据库连接
db.close((err) => {
if (err) {
console.error("Error closing database", err);
} else {
console.log("Database closed.");
}
});
} catch (error) {
console.error("An error occurred:", error);
}
})();