Flutter对象关系映射插件simple_orm的使用
Flutter对象关系映射插件simple_orm的使用
本工程是基于sqflite实现的简易版本的ORM,优点是支持在不更新数据库版本的情况下新增表字段,解决表结构变更时需要升级数据库版本的问题。
接入方法
1. 设置依赖
在pubspec.yaml
文件中添加以下依赖:
dependencies:
flutter:
sdk: flutter
simple_orm:
path: ../simple_orm
simple_orm_annotation:
path: ../annotation
dev_dependencies:
flutter_test:
sdk: flutter
simple_orm_generator:
path: ../generator
build_runner: ^2.4.8
analyzer: ^6.2.0
2. 创建entity
需要把entity放在lib/db/entity/
目录下面。
import 'package:simple_orm_annotation/annotation/column_info.dart';
import 'package:simple_orm_annotation/annotation/table.dart';
@Table(name: 'user_info', index: {'sex_index': ['sex']})
class UserInfo {
@ColumnInfo(name: 'id', primaryKey: true, autoIncrement: true)
int? id;
@ColumnInfo(name: 'username')
String? username;
@ColumnInfo(name: 'nickname')
String? nickname;
@ColumnInfo(name: 'sex')
String? sex;
@ColumnInfo(name: 'address')
String? address;
}
3. 执行build_runner命令
运行以下命令生成dao文件:
flutter packages pub run build_runner build
生成的dao文件将位于lib/db/dao/generated/
目录下。
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// DbGenerator
// **************************************************************************
// NOTE: 可以直接使用该生成类,建议最好继承生成类再使用
import 'package:simple_orm/base_dao.dart';
import 'package:sqflite/sqflite.dart';
class BaseUserInfoDao extends BaseDao<UserInfo> {
static String tableName = "user_info";
static late Database db;
static const String columnId = "id";
static const String columnUsername = "username";
static const String columnNickname = "nickname";
static const String columnSex = "sex";
static const String columnAddress = "address";
static String _createTableSQL() {
return "CREATE TABLE IF NOT EXISTS `user_info` (`id` INTEGER PRIMARY KEY autoincrement,`username` TEXT,`nickname` TEXT,`sex` TEXT,`address` TEXT)";
}
static Map<String, String> _columnMap() => {
columnId: 'INTEGER',
columnUsername: 'TEXT',
columnNickname: 'TEXT',
columnSex: 'TEXT',
columnAddress: 'TEXT',
};
static List<String>? _indexList() {
return const [
'CREATE INDEX IF NOT EXISTS `sex_index` ON user_info (`sex`);'
];
}
static _createTable() async {
await db.execute(_createTableSQL());
}
static _createIndex() async {
// 创建索引
final indexs = _indexList();
if (indexs != null) {
for (var indexString in indexs) {
if (indexString.isNotEmpty) {
await db.execute(indexString);
}
}
}
}
static _updateCols() async {
final oldCols = await getTableInfo();
final newCols = _columnMap();
List<String> updateSQLs = [];
// 检查新增字段
newCols.forEach((key, value) {
if (!oldCols.containsKey(key)) {
updateSQLs.add('ALTER TABLE $tableName ADD COLUMN $key $value;');
}
});
if (updateSQLs.isNotEmpty) {
for (var sql in updateSQLs) {
await db.execute(sql);
}
}
}
static getTableInfo() async {
ensureDB();
var ret = await db.rawQuery('PRAGMA table_info("$tableName")');
if (ret != null && ret.isNotEmpty) {
Map<String, String> result = {};
for (var element in ret) {
result[element['name'] as String] = element['type'] as String;
}
return result;
} else {
return {};
}
}
static ensureDB() {
if (db == null) {
throw Exception('should invoke initTable first');
}
}
static Future initTable(Database _db) async {
db = _db;
// 创建表
await _createTable();
// 更新字段
await _updateCols();
// 创建索引
await _createIndex();
}
@override
Future<bool> insertOrUpdate(UserInfo entity) async {
ensureDB();
Map<String, Object> values = {};
if (entity.id != null && !entity.id!.isNaN) {
values['id'] = entity.id!;
}
if (entity.username != null && entity.username!.isNotEmpty) {
values['username'] = entity.username!;
}
if (entity.nickname != null && entity.nickname!.isNotEmpty) {
values['nickname'] = entity.nickname!;
}
if (entity.sex != null && entity.sex!.isNotEmpty) {
values['sex'] = entity.sex!;
}
if (entity.address != null && entity.address!.isNotEmpty) {
values['address'] = entity.address!;
}
int ret = await db.insert(tableName, values,
conflictAlgorithm: ConflictAlgorithm.replace);
return ret != 0;
}
@override
Future<UserInfo?> getById(dynamic id) async {
ensureDB();
final valuesList = await db.rawQuery('SELECT * FROM user_info WHERE id = ?', [id]);
if (valuesList.isEmpty) {
return null;
}
final values = valuesList[0];
final item = UserInfo();
item.id = values['id'] as int?;
item.username = values['username'] as String?;
item.nickname = values['nickname'] as String?;
item.sex = values['sex'] as String?;
item.address = values['address'] as String?;
return item;
}
@override
Future<UserInfo?> getFirstOrNull(UserInfo entity) async {
ensureDB();
final list = await getList(entity);
if (list.isEmpty) {
return null;
}
return list[0];
}
@override
Future<List<UserInfo?>> getList([UserInfo? entity]) async {
ensureDB();
String querySql = 'SELECT * FROM user_info';
if (entity != null) {
StringBuffer whereSb = StringBuffer(' WHERE 1=1');
if (entity.id != null && !entity.id!.isNaN) {
whereSb.write(' AND ');
whereSb.write('id=${entity.id}');
}
if (entity.username != null && entity.username!.isNotEmpty) {
whereSb.write(' AND ');
whereSb.write('username=${entity.username}');
}
if (entity.nickname != null && entity.nickname!.isNotEmpty) {
whereSb.write(' AND ');
whereSb.write('nickname=${entity.nickname}');
}
if (entity.sex != null && entity.sex!.isNotEmpty) {
whereSb.write(' AND ');
whereSb.write('sex=${entity.sex}');
}
if (entity.address != null && entity.address!.isNotEmpty) {
whereSb.write(' AND ');
whereSb.write('address=${entity.address}');
}
querySql = querySql + whereSb.toString();
}
final valuesList = await db.rawQuery(querySql);
List<UserInfo> ret = [];
for (var values in valuesList) {
final item = UserInfo();
item.id = values['id'] as int?;
item.username = values['username'] as String?;
item.nickname = values['nickname'] as String?;
item.sex = values['sex'] as String?;
item.address = values['address'] as String?;
ret.add(item);
}
return ret;
}
@override
Future<bool> delete([UserInfo? entity]) async {
ensureDB();
if (entity == null) {
await db.execute('DELETE FROM user_info');
return true;
}
String deleteSql = 'DELETE FROM user_info WHERE 1=1 ';
StringBuffer whereSb = StringBuffer();
if (entity.id != null && !entity.id!.isNaN) {
whereSb.write(' AND ');
whereSb.write('id=${entity.id}');
}
if (entity.username != null && entity.username!.isNotEmpty) {
whereSb.write(' AND ');
whereSb.write('username=${entity.username}');
}
if (entity.nickname != null && entity.nickname!.isNotEmpty) {
whereSb.write(' AND ');
whereSb.write('nickname=${entity.nickname}');
}
if (entity.sex != null && entity.sex!.isNotEmpty) {
whereSb.write(' AND ');
whereSb.write('sex=${entity.sex}');
}
if (entity.address != null && entity.address!.isNotEmpty) {
whereSb.write(' AND ');
whereSb.write('address=${entity.address}');
}
deleteSql = deleteSql + whereSb.toString();
final ret = await db.rawDelete(deleteSql);
return ret != 0;
}
@override
Future<int> updateValues(
Map<String, Object> updateValues, Map<String, Object> whereArgs) async {
ensureDB();
final whereSb = StringBuffer('1 = 1');
if (whereArgs.isNotEmpty) {
for (var ele in whereArgs.entries) {
whereSb.write(' AND ');
whereSb.write('${ele.key} = ${ele.value}');
}
return await db.update(tableName, updateValues,
where: whereSb.toString());
}
return 0;
}
}
4. 继承dao类
import 'package:simple_orm_example/db/dao/generated/base_user_info_dao.dart';
class UserInfoDao extends BaseUserInfoDao {
static UserInfoDao? _instance;
factory UserInfoDao() => _instance ??= UserInfoDao._();
UserInfoDao._();
}
5. 使用dao
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final db = await initDB();
await BaseUserInfoDao.initTable(db);
runApp(const MyApp());
}
initDB() async {
// open the database
final databasesPath = await getDatabasesPath();
final dbPath = "$databasesPath/simple_orm_example.db";
return await openDatabase(
dbPath,
version: 1,
onCreate: (Database db, int version) async {},
onUpgrade: (Database db, int oldVersion, int newVersion) async {},
);
}
getUserList() {
UserInfoDao().getList().then((value) {
print('user count: ${value.length}');
});
}
_addUser() {
UserInfoDao().insertOrUpdate(UserInfo()
..username = 'user_1'
..nickname = 'nickname_1'
..address = 'address_1'
..sex = 'male'
).then((value) {
print('insert user result: $value');
});
}
Annotation
table.dart
class Table {
/// 表名
final String? name;
/// 索引,"索引名": ["字段1", "字段2"]
final Map<String, List<String>>? index;
const Table({this.name, this.index});
}
column_info.dart
class ColumnInfo {
/// 字段名
final String? name;
/// 是否是主键
final bool primaryKey;
/// 是否自增——只有int类型支持自增
final bool? autoIncrement;
const ColumnInfo({this.name, this.primaryKey = false, this.autoIncrement});
}
更多关于Flutter对象关系映射插件simple_orm的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter对象关系映射插件simple_orm的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
simple_orm
是一个用于 Flutter 的轻量级对象关系映射(ORM)插件,它可以帮助开发者简化数据库操作。通过 simple_orm
,你可以将 Dart 对象直接映射到数据库表,从而避免手动编写 SQL 语句。
安装
首先,你需要在 pubspec.yaml
文件中添加 simple_orm
依赖:
dependencies:
simple_orm: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
基本用法
1. 定义实体类
使用 simple_orm
,你需要定义一个实体类,并使用注解来标记它。例如:
import 'package:simple_orm/simple_orm.dart';
@Entity(tableName: 'users')
class User {
@PrimaryKey(autoIncrement: true)
int? id;
@ColumnInfo(name: 'user_name')
String? userName;
@ColumnInfo(name: 'email')
String? email;
User({this.id, this.userName, this.email});
}
@Entity(tableName: 'users')
:标记该类为实体类,并指定对应的数据库表名。@PrimaryKey(autoIncrement: true)
:标记该字段为主键,并指定是否自增。@ColumnInfo(name: 'user_name')
:标记该字段为数据库列,并指定列名。
2. 初始化数据库
在使用 simple_orm
之前,你需要初始化数据库:
import 'package:simple_orm/simple_orm.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化数据库
await SimpleOrm.init(
databaseName: 'my_database.db',
version: 1,
entities: [User],
);
runApp(MyApp());
}
3. 插入数据
你可以使用 SimpleOrm.insert
方法将对象插入数据库:
User user = User(userName: 'JohnDoe', email: 'johndoe@example.com');
int id = await SimpleOrm.insert(user);
print('Inserted user with id: $id');
4. 查询数据
你可以使用 SimpleOrm.query
方法查询数据:
List<User> users = await SimpleOrm.query(User);
users.forEach((user) {
print('User: ${user.userName}, Email: ${user.email}');
});
5. 更新数据
你可以使用 SimpleOrm.update
方法更新数据:
User user = users.first;
user.email = 'newemail@example.com';
await SimpleOrm.update(user);
6. 删除数据
你可以使用 SimpleOrm.delete
方法删除数据:
await SimpleOrm.delete(user);
高级用法
条件查询
simple_orm
支持条件查询,你可以使用 where
参数来指定查询条件:
List<User> users = await SimpleOrm.query(
User,
where: 'user_name = ?',
whereArgs: ['JohnDoe'],
);
自定义查询
你还可以执行自定义的 SQL 查询:
List<Map<String, dynamic>> results = await SimpleOrm.rawQuery(
'SELECT * FROM users WHERE email = ?',
['johndoe@example.com'],
);
数据库迁移
如果你的数据库结构发生了变化,你可以通过增加版本号来执行数据库迁移:
await SimpleOrm.init(
databaseName: 'my_database.db',
version: 2, // 增加版本号
entities: [User],
);