如何在交易中使用其他回购协议

How to use other repos in a transactions

我有几个带有方法的回购协议,其中一些方法使用事务 (.tx)。 例如,在我下面的 DevicesRepository 中,'add' 方法必须插入一个新设备,这意味着: 1. 插入系统和 return ID (SystemsRepository) 2.插入带有returner systemId的设备并获取新的id 3. 插入使用 deviceId

的其他片段(其他回购)

我的问题是在那笔交易中我不知道如何访问其他回购方法。 我可以使用我的数据库对象中的其他存储库(Database.systems.add、Database.OtherRepo.add、[...]),但如果我这样做

tx doc

When invoked on the root Database object, the method allocates the connection from the pool, executes the callback, and once finished - releases the connection back to the pool. However, when invoked inside another task or transaction, the method reuses the parent connection.

task doc

When executing more than one request at a time, one should allocate and release the connection only once, while executing all the required queries within the same connection session. More importantly, a transaction can only work within a single connection.

谢谢! :)

P.S : 我可以添加我如何初始化数据库和 repos

./db/repos/devices.js

'use strict';

var Database = null, pgp = null, Collections = null;

async function add(params) {
  // I can use Database.systems.add
  return Database.tx('Insert-New-Device', async function(transaction) {
    let device = params.data.device;

    const system = await transaction.systems.add(params);
    device.systemid = system.systemId;

    const query = pgp.helpers.insert(device, Collections.insert);
    query += " RETURNING deviceId";
    device.deviceId = await transaction.one(query);

    const OtherRepoInsert = await transaction.otherRepos.add(params);
    device.otherRepos.id = OtherRepoInsert.otherReposId;

    return device
  })
  .then(data => { return data; })
  .catch(ex => { throw new Error(ex); });
}

function createColumnsets() { /* hidden for brevity (almost the same as the pg-promise-demo */ }

const DevicesRepository = {
  add: add
};


module.exports = (db) => {
  Database = db;
  pgp = db.$config.pgp;
  Collections = createColumnsets();

  return DevicesRepository;
}

./db/repos/systems.js

'use strict';

var Database = null, pgp = null, Collections = null;

async function add(params) {
  var system = params.data.system;
  system.archid=2;
  system.distributionid=3;

  var query = pgp.helpers.insert(system, Collections.insert);
  if(params.return) query += " RETURNING *";

  return Database.any(query)
                  .then(data => { return data; })
                  .catch(ex => { throw new Error(ex); });
}

function createColumnsets() { /* hidden for brevity (almost the same as the pg-promise-demo */ }

const SystemsRepository = {
  add: add
};

module.exports = (db) => {
  Database = db;
  pgp = db.$config.pgp;
  Collections = createColumnsets();

  return SystemsRepository;
}

您可以在调用之外建立事务,然后将其传递给那些函数以供它们使用。

就是说,我建议稍微研究一下 higher-level 查询生成器库,例如 Knex.js,以免您遇到这些(以及将来)的麻烦。

我找到了真正的问题。

如果你去我的第一个 post,你可以看到我的每个 repo 都导出了一个初始化函数: 1. 由 pg-promise 'extend' 事件调用 2. 接受一个参数:上下文 3. 使用此参数通过 db.$config.pgp

初始化 repo 中的 'pgp' 变量

demo 中所述,此事件发生在应用程序中第一次为每个任务和事务加载数据库时。

以我为例: 事件第一次发生时(完整的应用程序初始化),事件的参数 'obj' 是 database context(包含 $config、$pool、...)所以它有效 当任务或事务发生事件时,事件的参数 'obj' 是 Task context,其中 $config 不存在,因此事件无法使用我的 repo 扩展上下文。抛出异常 'can not read property helpers of undefined' 但没有出现,也没有使我的应用程序崩溃,我不知道为什么,可能在事件中被捕获了。这就是为什么我不能在交易中使用我的回购。

我像这样修改了我的代码并且它有效:

./db/index.js

'use strict';
/* hidden for brevity */
// pg-promise initialization options:
const initOptions = {
    promiseLib: promise,
    extend(obj, dc) {
        obj.roles = repos.Roles(obj, pgp);
        obj.shells = repos.Shells(obj, pgp);
        obj.systems = repos.Systems(obj, pgp);
        obj.devices = repos.Devices(obj, pgp);
    }
};

const pgp = require('pg-promise')(initOptions);
const db = pgp(config);

/* hidden for brevity */

./db/index.js

'use strict';
/* hidden for brevity */
// pg-promise initialization options:
const initOptions = {
    promiseLib: promise,
    extend(obj, dc) {
        obj.roles = repos.Roles(obj, pgp);
        obj.shells = repos.Shells(obj, pgp);
        obj.systems = repos.Systems(obj, pgp);
        obj.devices = repos.Devices(obj, pgp);
    }
};

const pgp = require('pg-promise')(initOptions);
const db = pgp(config);

/* hidden for brevity */

./db/repos/{repoFiles}.js

/* hidden for brevity */
module.exports = (db, pgpLib) => {
  Database = db;
  pgp = pgpLib;
  Collections = createColumnsets();

  return DevicesRepository;
}

属性 $config is there for integration purposes. That's why it exists only on the root Database 级别,并且不在任务或事务中。

为了利用 helpers namespace, you should pass pgp into repositories when you initialize them, as shown within pg-promise-demo:

 extend(obj, dc) {
        obj.users = new repos.Users(obj, pgp);
        obj.products = new repos.Products(obj, pgp);
    }