typeorm 在 expo app 里的使用示例
本帖最后由 HelloWorld 于 2025-1-5 11:54 编辑最近在写个 app 需要用到 sqlite,选择 orm 时,本来打算用 Prisma,但是这个必须 node 环境,expo 用不了
另一个比较流行的是 typeorm,查了一下,他们官方提供了 expo 例子:https://github.com/typeorm/expo-example ,将这个仓库拉本地运行直接失败,毕竟 6 年前老项目,expo 版本也不兼容了
于是自己新建一个 expo-router 项目:https://docs.expo.dev/router/installation ,然后将 expo-example 的页面代码和 entities 拷贝到 expo-router 项目里
由于 typeorm 用到装饰器,所以需要在 tsconfig.json 里添加 compilerOptions.experimentalDecorators 和 compilerOptions.emitDecoratorMetadata 并且值都设为 true
然后运行,一堆报错,其中一个可能是因为 expo-example 用的类组件搬到 expo-router 里无法被 tab 识别,于是将整个页面改成 function 组件,代码会放到帖子末尾
改了 function 组件运行再次报错,将错误消息拿去问 gemini,说在 entity 里需要设置变量类型,于是设置 @Column({type: 'string'}),运行又报错,再次问 gemini,它说 sqlite 没有 string 类型,于是用了 text,运行成功:
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm/browser";
@Entity('category')
export class Category {
@PrimaryGeneratedColumn()
id!: number;
@Column({ type: 'text' })
name!: string;
}
上文提到的类组件页面代码改成函数组件:
import React, { useEffect, useState } from 'react'
import {
StyleSheet,
Text,
View,
Button,
Alert
} from 'react-native';
import { DataSource } from 'typeorm/browser';
import { Category } from '@/database/entities/category';
import { Author } from '@/database/entities/author';
import { Post } from '@/database/entities/post';
import * as FileSystem from 'expo-file-system'
const database = 'test19.db' // without .db as extension is ok, but recommanded
const dataSource = new DataSource({
database,
driver: require('expo-sqlite'),
entities: [
Category,
Author,
Post
],
synchronize: true,
type: "expo",
})
export default function SqlitePage() {
const = useState('')
const = useState<Post>()
function connect() {
return dataSource.initialize()
}
useEffect(() => {
runDemo()
}, [])
async function runDemo() {
const source = await connect();
const category1 = new Category();
category1.name = "TypeScript";
const category2 = new Category();
category2.name = "Programming";
const author = new Author();
author.name = "Person";
const post = new Post();
post.title = "Control flow based type analysis";
post.text = "TypeScript 2.0 implements a control flow-based type analysis for local variables and parameters.";
post.categories = ;
post.author = author;
const postRepository = source.getRepository(Post);
await postRepository.save(post);
console.log("Post has been saved");
setProgress("Post has been saved")
const loadedPost = await postRepository.findOne({ where: { id: post.id }, relations: ["author", "categories"] });
if (loadedPost) {
console.log("Post has been loaded: ", loadedPost);
setLoadedPost(loadedPost)
}
}
async function checkSqliteFile() {
const dataDirectory = FileSystem.documentDirectory || FileSystem.cacheDirectory;
const databaseFilePath = `${dataDirectory}SQLite/${database}`
console.log('databaseFilePath', databaseFilePath)
try {
const fileInfo = await FileSystem.getInfoAsync(databaseFilePath);
const fileExists = fileInfo.exists;
Alert.alert(`fileExists: ${fileExists}`, databaseFilePath)
} catch (error) {
console.error('Error getting file info:', error);
}
}
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to the Expo Example for TypeORM!
</Text>
<Text style={styles.small}>
{progress}
</Text>
<Text style={styles.small}>
{JSON.stringify(loadedPost)}
</Text>
<Button title='If sqlite file exists' onPress={checkSqliteFile} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
small: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
点击页面里的“If sqlite file exists”按钮,terminal log 会打印出 sqlite 数据库文件路径,按住 cmd 点击路径可以打开文件,如果你的 vscode 装了 SQLite Viewer 可以直接查看数据库内容
页:
[1]