前言
本文主讲在 electron 中使用 typeOrm 和 better-sqlite3 实现本地数据存储以及读取,以及开发过程中遇到问题的解决方案
阅读须知:
- 代码使用 TypeScript,vue-setup
- 脚手架 electron-vite
- 开发环境:window,node:v16.15.1,pnpm:v7.9.0
本文知识点
- 用 typeOrm 创建连接时,在 Electron 中需要调整的参数
- 解决 better-sqlite3 使用内置 node 版本和项目使用的 Electron 内置 node 版本不一致
主进程编写
安装
pnpm i typeorm
pnpm i better-sqlite3
实现连接数据库方法
// src\main\service\database.ts
import path from "path";
import { DataSource } from "typeorm";
import { app } from "electron";
import { is } from "@electron-toolkit/utils";
import { BetterSqlite3ConnectionOptions } from "typeorm/driver/better-sqlite3/BetterSqlite3ConnectionOptions";
import { MessageModel } from "./model";
export class DataBase {
dataSource: DataSource;
//初始化数据库文件
constructor(database: string) {
//使用该方法获取缓存目录从而实现软件升级或卸载数据保留
// 例:windows下文件存储位置
// C:\Users\WHWAN\AppData\Roaming\pc-client\data\message.db
let basePath = path.join(
app.getPath("appData"),
app.getName(),
`./data/${database}.db`
);
let options: BetterSqlite3ConnectionOptions = {
type: "better-sqlite3",
entities: [MessageModel],
database: basePath,
synchronize: true,
};
this.dataSource = new DataSource(options);
}
}
使用出现如下报错
Error: The module '...node_modules\better-sqlite3\build\Release\better_sqlite3.node'
was compiled against a different Node.js version using
NODE_MODULE_VERSION $XYZ. This version of Node.js requires
NODE_MODULE_VERSION $ABC. Please try re-compiling or re-installing
the module (for instance, using `npm rebuild` or `npm install`).
安装
pnpm i -D electron-rebuild
在package.json中添加命令并执行,即可构建对应版本better-sqlite3
"rebuild": "electron-rebuild -f -w better-sqlite3"
使用示例
创建表结构
import { Entity, PrimaryColumn, Column } from "typeorm";
@Entity()
export class MessageModel {
@PrimaryColumn({ type: "int" })
id: number | undefined;
@Column({ type: "int8", nullable: false })
roomId: number | undefined;
@Column({ type: "text", nullable: false })
content: string | undefined;
@Column({ type: "text", nullable: false })
type: string | undefined;
}
实现 CRUD
主进程实现
// src\main\service\messageService.ts
import { ipcMain } from "electron";
import { DataSource } from "typeorm";
import { WindowsMain } from "../windows";
import { DataBase } from "./database";
//创建数据查询Modal
export interface MsgListDTO extends ListDTO {
roomId: number;
}
//列表查询基类
export interface ListDTO {
pageNum: number;
pageSize: number;
sort: number;
}
//实现MessageService
export class MessageService {
static instance: MessageService;
dataSource: DataSource;
//使用单例模式
static getInstance() {
if (!this.instance) {
this.instance = new MessageService();
}
return this.instance;
}
constructor() {
//创建数据库
this.dataSource = new DataBase("message").dataSource;
}
//初始化主角进程监听事件
init() {
//新增数据监听
ipcMain.on(
"create-message",
async (_event, data: { winViewId: number; val: MessageModel }) => {
const info = new MessageModel();
info.roomId = data.val.roomId;
info.content = data.val.content;
info.type = data.val.type;
const res = await this.create(info);
const win = WindowsMain.getInstance().getWin(data.winViewId);
win && win.webContents.send("update-messages", res);
}
);
//获取数据列表监听
ipcMain.on(
"get-message",
async (_event, data: { winViewId: number; params: MsgListDTO }) => {
const res = await this.getList(data.params);
const win = WindowsMain.getInstance().getWin(data.winViewId);
win && win.webContents.send("get-messages", res);
}
);
}
//实现新增方法
async create(message: MessageModel) {
await this.dataSource.initialize();
const res = await this.dataSource.manager.save(message);
await this.dataSource.destroy();
return res;
}
//实现分页查询
async getList(options: MsgListDTO) {
await this.dataSource.initialize();
const skip = options.pageSize * options.pageNum - options.pageSize;
const sort = options.sort === 2 ? "ASC" : "DESC";
const listAndCount = await this.dataSource
.createQueryBuilder(MessageModel, "message")
.where(`message.roomId = ${options.roomId}`)
.orderBy("message.id", sort)
.skip(skip)
.take(options.pageSize)
.getManyAndCount();
await this.dataSource.destroy();
return { list: listAndCount[0], count: listAndCount[1] };
}
}
渲染进程新增及查询
//创建消息体
export interface MessageSqlModel {
id?: number;
roomId: number;
content: string;
type: string;
}
const message = ref<MessageSqlModel>({
roomId: 1,
content: "你好",
type: "text",
});
//发送消息
const onSend = () => {
window.electron.ipcRenderer.send("create-message", {
winViewId: window.winViewId,
val: { ...message.value },
});
};
//获取更新消息
window.electron.ipcRenderer.on("update-messages", (_event, data) => {
console.log("update-messages", data);
});
//分页查询
window.electron.ipcRenderer.on("get-messages", (_event, data) => {
console.log("get-messages", data);
});
window.electron.ipcRenderer.send("get-message", {
winViewId: window.winViewId,
params: {
roomId: 1,
sort: "ASC",
pageNum: 1,
pageSize: 5,
},
});
后记
本文为学习中记录一下遇到的问题 欢迎交流
参考文档
- [Electron 文档]www.electronjs.org/zh/docs/lat…
- [typeorm 官网参数]typeorm.io/data-source…
- [better-sqlite3-issues]github.com/WiseLibs/be…
- [better-sqlite3-issues]github.com/WiseLibs/be…