Flutter数据库连接插件pip_services4_postgres的使用

Flutter数据库连接插件pip_services4_postgres的使用

Pip.Services Logo
PostgreSQL组件在Dart中的应用

该模块是Pip.Services多语言微服务工具包的一部分。它提供了一组用于实现PostgreSQL持久化的组件。

该模块包含以下包:

  • Build - 创建PostgreSQL持久化组件的工厂。
  • Connect - 配置到数据库的PostgreSQL连接组件。
  • Persistence - 执行基本CRUD操作的抽象持久化组件。

快速链接

使用

在你的pubspec.yaml文件中添加依赖项:

dependencies:
  pip_services4_postgres: ^1.0.0

例如,我们创建一个持久化对象如下:

import 'package:pip_services3_commons/pip_services3_commons.dart';

class MyObject implements IStringIdentifiable, ICloneable {
  @override
  String? id;
  String? key;
  String? content;

  MyObject();

  MyObject.from(this.id, this.key, this.content);

  Map<String, dynamic> toJson() {
    return {'id': id, 'key': key, 'content': content};
  }

  void fromJson(Map<String, dynamic> json) {
    id = json['id'];
    key = json['key'];
    content = json['content'];
  }

  @override
  MyObject clone() {
    return MyObject.from(id, key, content);
  }
}

持久化组件应实现以下接口,包括一组基本的CRUD操作:

abstract class IMyPersistence {
  Future<DataPage<MyObject>> getPageByFilter(
      IContext? context, FilterParams? filter, PagingParams? paging);

  Future<MyObject?> getOneById(IContext? context, String id);

  Future<MyObject?> getOneByKey(IContext? context, String key);

  Future<MyObject?> create(IContext? context, MyObject? item);

  Future<MyObject?> update(IContext? context, MyObject? item);

  Future<MyObject?> set(IContext? context, MyObject? item);

  Future<MyObject?> deleteById(IContext? context, String? id);
}

要实现PostgreSQL持久化组件,可以继承IdentifiablePostgresPersistence。大多数CRUD操作将来自基类。你只需要覆盖getPageByFilter方法,并实现一个在基类中不存在的getOneByKey自定义持久化方法。

class MyPostgresPersistence
    extends IdentifiablePostgresPersistence<MyObject, String> {
  MyPostgresPersistence() : super('myobjects', null) {
    ensureSchema_(
        "CREATE TABLE myobjects (id VARCHAR(32) PRIMARY KEY, key VARCHAR(50), content VARCHAR(255))");
    ensureIndex_("myobjects_key", {'key': 1}, {'unique': true});
  }

  @override
  void defineSchema_() {
    // pass
  }

  String? _composeFilter(FilterParams? filter) {
    filter = filter ?? FilterParams();

    var criteria = [];

    var id = filter.getAsNullableString('id');
    if (id != null) criteria.add("id='" + id + "'");

    var tempIds = filter.getAsNullableString("ids");
    if (tempIds != null) {
      var ids = tempIds.split(",");
      criteria.add("id IN ('" + ids.join("','") + "')");
    }

    var key = filter.getAsNullableString("key");
    if (key != null) criteria.add("key='" + key + "'");

    return criteria.isNotEmpty ? criteria.join(" AND ") : null;
  }

  Future<DataPage<MyObject>> getPageByFilter(
      IContext? context, FilterParams? filter, PagingParams? paging) {
    return super.getPageByFilter_(
        context, _composeFilter(filter), paging, null, null);
  }

  Future<MyObject?> getOneByKey(IContext? context, String key) async {
    var query =
        "SELECT * FROM " + this.quotedTableName_() + " WHERE \"key\"=@1";
    var params = {'1': key};

    var res = await client_!.query(query, substitutionValues: params);

    var resValues = res.isNotEmpty ? res.first[0][1] : null;

    var item = this.convertToPublic_(resValues);

    if (item == null)
      this.logger_.trace(context, "Nothing found from %s with key = %s",
          [this.tableName_, key]);
    else
      this.logger_.trace(context, "Retrieved from %s with key = %s",
          [this.tableName_, key]);

    item = this.convertToPublic_(item);
    return item;
  }
}

你也可以选择以非关系型格式存储数据,使用IdentificableJsonPostgresPersistence。它将数据存储在两个列的表中——id为唯一对象ID,data为序列化为JSON的对象数据。访问数据字段时,应使用data->'field'表达式或data->>'field'表达式(对于字符串值)。

class MyPostgresJsonPersistence
    extends IdentifiableJsonPostgresPersistence<MyObject, String> {
  MyPostgresJsonPersistence() : super('myobjects_json', null) {
    clearSchema();
    ensureTable_(idType: "VARCHAR(32)", dataType: "JSONB");
    ensureIndex_(this.tableName_! + '_json_key', {"(data->>'key')": 1},
        {'unique': true});
  }

  @override
  void defineSchema_() {
    // pass
  }

  String? _composeFilter(FilterParams? filter) {
    filter = filter ?? FilterParams();

    var criteria = [];

    var id = filter.getAsNullableString('id');
    if (id != null) criteria.add("data->>'id'='" + id + "'");

    var tempIds = filter.getAsNullableString("ids");
    if (tempIds != null) {
      var ids = tempIds.split(",");
      criteria.add("data->>'id' IN ('" + ids.join("','") + "')");
    }

    var key = filter.getAsNullableString("key");
    if (key != null) criteria.add("data->>'key'='" + key + "'");

    return criteria.isNotEmpty ? criteria.join(" AND ") : null;
  }

  Future<DataPage<MyObject>> getPageByFilter(
      IContext? context, FilterParams? filter, PagingParams? paging) {
    return super.getPageByFilter_(
        context, _composeFilter(filter), paging, 'id', null);
  }

  Future<MyObject?> getOneByKey(IContext? context, String key) async {
    var query =
        "SELECT * FROM " + this.quotedTableName_() + " WHERE data->>'key'=@1";
    var params = {'1': key};

    var res = await client_!.query(query, substitutionValues: params);

    var resValues = res.isNotEmpty ? res.first[0][1] : null;

    var item = this.convertToPublic_(resValues);

    if (item == null)
      this.logger_.trace(context, "Nothing found from %s with key = %s",
          [this.tableName_, key]);
    else
      this.logger_.trace(context, "Retrieved from %s with key = %s",
          [this.tableName_, key]);

    item = this.convertToPublic_(item);
    return item;
  }
}

配置你的微服务,使其包含PostgreSQL持久化可能如下所示:

...
{{#if POSTGRES_ENABLED}}
- descriptor: pip-services:connection:postgres:con1:1.0
  connection:
    uri: {{{POSTGRES_SERVICE_URI}}}
    host: {{{POSTGRES_SERVICE_HOST}}}{{#unless POSTGRES_SERVICE_HOST}}localhost{{/unless}}
    port: {{POSTGRES_SERVICE_PORT}}{{#unless POSTGRES_SERVICE_PORT}}5432{{/unless}}
    database: {{POSTGRES_DB}}{{#unless POSTGRES_DB}}app{{/unless}}
  credential:
    username: {{POSTGRES_USER}}
    password: {{POSTGRES_PASS}}
    
- descriptor: myservice:persistence:postgres:default:1.0
  dependencies:
    connection: pip-services:connection:postgres:con1:1.0
  table: {{POSTGRES_TABLE}}{{#unless POSTGRES_TABLE}}myobjects{{/unless}}
{{/if}}
...

现在你可以从命令行安装包:

pub get

开发

对于开发,你需要安装以下前置条件:

  • Dart SDK 3
  • Visual Studio Code 或其他IDE
  • Docker

安装依赖项:

pub get

运行自动化测试:

pub run test

生成API文档:

./docgen.ps1

在提交更改之前,运行docker化构建和测试:

./build.ps1
./test.ps1
./clear.ps1

更多关于Flutter数据库连接插件pip_services4_postgres的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据库连接插件pip_services4_postgres的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


pip_services4_postgres 是一个用于连接和操作 PostgreSQL 数据库的插件,它是 pip_services4 微服务工具包的一部分。这个插件可以帮助你在 Flutter 应用中轻松地连接到 PostgreSQL 数据库,并执行各种数据库操作。

以下是使用 pip_services4_postgres 插件的步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 pip_services4_postgres 插件的依赖。

dependencies:
  pip_services4_postgres: ^0.0.1

然后运行 flutter pub get 来获取依赖。

2. 创建数据库连接

接下来,你需要在代码中创建一个 PostgresConnection 对象来连接到 PostgreSQL 数据库。

import 'package:pip_services4_postgres/pip_services4_postgres.dart';

void main() async {
  var connection = PostgresConnection();
  connection.configure(ConfigParams.fromTuples([
    'connection.host', 'localhost',
    'connection.port', 5432,
    'connection.database', 'testdb',
    'connection.username', 'user',
    'connection.password', 'password'
  ]));

  await connection.open(null);

  // 在这里执行数据库操作

  await connection.close(null);
}

3. 执行 SQL 查询

你可以使用 PostgresConnection 对象来执行 SQL 查询。

var result = await connection.query('SELECT * FROM users');
for (var row in result) {
  print(row);
}

4. 使用事务

你也可以使用事务来执行多个 SQL 操作。

await connection.beginTransaction(null);

try {
  await connection.execute('INSERT INTO users (name, email) VALUES (\'John Doe\', \'john@example.com\')');
  await connection.execute('UPDATE users SET email = \'johndoe@example.com\' WHERE name = \'John Doe\'');
  await connection.commitTransaction(null);
} catch (e) {
  await connection.rollbackTransaction(null);
}

5. 关闭连接

完成数据库操作后,记得关闭连接。

await connection.close(null);

6. 处理错误

在处理数据库操作时,确保捕获并处理可能出现的错误。

try {
  await connection.open(null);
  var result = await connection.query('SELECT * FROM users');
  print(result);
} catch (e) {
  print('Error: $e');
} finally {
  await connection.close(null);
}

7. 配置连接参数

你可以通过 ConfigParams 来配置数据库连接参数,例如主机名、端口、数据库名称、用户名和密码。

connection.configure(ConfigParams.fromTuples([
  'connection.host', 'localhost',
  'connection.port', 5432,
  'connection.database', 'testdb',
  'connection.username', 'user',
  'connection.password', 'password'
]));

8. 使用连接池

如果你需要处理多个并发请求,可以使用连接池来提高性能。

var connection = PostgresConnection();
connection.configure(ConfigParams.fromTuples([
  'connection.host', 'localhost',
  'connection.port', 5432,
  'connection.database', 'testdb',
  'connection.username', 'user',
  'connection.password', 'password',
  'options.max_pool_size', 10
]));

await connection.open(null);

9. 使用 ORM

pip_services4_postgres 也支持使用 ORM(对象关系映射)来简化数据库操作。你可以定义实体类,并使用 ORM 进行 CRUD 操作。

class User {
  int id;
  String name;
  String email;

  User({this.id, this.name, this.email});

  factory User.fromMap(Map<String, dynamic> map) {
    return User(
      id: map['id'],
      name: map['name'],
      email: map['email'],
    );
  }

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'name': name,
      'email': email,
    };
  }
}

var users = await connection.query('SELECT * FROM users');
var userList = users.map((row) => User.fromMap(row)).toList();
回到顶部