反对 js:无法使用连接表额外属性更新多对多关系。说附加属性无效

Posted

技术标签:

【中文标题】反对 js:无法使用连接表额外属性更新多对多关系。说附加属性无效【英文标题】:Objection js: Can't update many to many relation with join table extra property. Says additional property is invalid 【发布时间】:2019-08-15 13:39:38 【问题描述】:

在 Postgres 上使用 ObjectionJS 而不是 knex,我无法修补与另一个模型具有多对多关系的模型的连接表中的额外属性。即使在关注并阅读和重新阅读文档时,我也无法更新该属性。即使文档列出的内容与我所做的完全相同。

基本上我有一个候补名单模型,该模型可能有很多用户,在这两者之间有一个连接表,它有一个“排名”属性,就像列表上的索引一样。 我正在尝试按照文档中提供的$relatedQuery 方法更新此排名属性

尝试了几种查询方法的组合,包括静态和实例;尝试为每个请求再次获取模型,尝试在两个模型上添加关系而不是单个模型(因为我不需要另一个模型来了解关系)但无济于事

为了比较,这是 ObjectionJS 文档中关于额外道具的内容的摘录,可以找到 here

const linda = await Actor
  .query()
  .findOne( name: 'Linda Hamilton' );

.
.
.

await linda
  .$relatedQuery('movies')
  .patch( characterName: 'Florence' )
  .where('movies.name', 'Curvature')

在某处的方法中,我执行以下操作

// At some point above, I do a query().findOne to get the waitlist
// trx is a transaction object
// id is the id of the user I want to update the rank of
        await waitlist
          .$relatedQuery('users', trx)
          .patch( rank: targetRank )
          .where( id )

这是一个非常愚蠢的迁移视图

  return knex.schema
    .createTable('users', (table) => 
      table
        .uuid('id')
        .primary()
        .notNullable()
      table.timestamp('createdAt').defaultTo(knex.fn.now())
      table.timestamp('updatedAt').defaultTo(knex.fn.now())
    )
    .createTable('waitlists', (table) => 
      table
        .uuid('id')
        .primary()
        .notNullable()
      table.timestamp('createdAt').defaultTo(knex.fn.now())
      table.timestamp('updatedAt').defaultTo(knex.fn.now())
    )
    .createTable('waitlists_users', (table) => 
      table.uuid('waitlistId')
      table
        .foreign('waitlistId')
        .references('id')
        .inTable('waitlists')
        .onDelete('CASCADE')
      table.uuid('userId')
      table
        .foreign('userId')
        .references('id')
        .inTable('users')
        .onDelete('CASCADE')
      table.primary(['waitlistId', 'userId'])
      table.integer('rank').index()
    )

最后是候补名单模型定义,不提供用户,因为这对该模型应该是完全透明的,它不关心它的排名变化

  static tableName = 'waitlists'

  static jsonSchema = 
    type: 'object',
    required: [],
    properties: ,
  

  static get relationMappings() 
    const UserModel = require('where/the/model/is/at').default

    return 
      users: 
        relation: ObjectionModel.ManyToManyRelation,
        modelClass: UserModel,
        join: 
          from: 'waitlists.id',
          through: 
            from: 'waitlists_users.waitlistId',
            to: 'waitlists_users.userId',
            extra: ['rank'],
          ,
          to: 'users.id',
        ,
      ,
    
  

执行上面那个微小的补丁查询会导致这个

ValidationError: rank: is an invalid additional property
      at Function.createValidationError (node_modules/objection/lib/model/Model.js:397:12)
      at parseValidationError (node_modules/objection/lib/model/AjvValidator.js:189:21)
      at AjvValidator.validate (node_modules/objection/lib/model/AjvValidator.js:78:19)
      at validate (node_modules/objection/lib/model/modelValidate.js:35:20)
      at UserModel.$validate (node_modules/objection/lib/model/Model.js:133:12)
      at setJson (node_modules/objection/lib/model/modelSet.js:28:16)
      at UserModel.$setJson (node_modules/objection/lib/model/Model.js:171:12)
      at Function.fromJson (node_modules/objection/lib/model/Model.js:320:11)
      at Function.ensureModel (node_modules/objection/lib/model/Model.js:630:25)
      at ManyToManyUpdateOperation.onAdd (node_modules/objection/lib/queryBuilder/operations/UpdateOperation.js:22:29)
      at ManyToManyUpdateOperation.onAdd (node_modules/objection/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js:28:23)
      at QueryBuilder.callOperationMethod (node_modules/objection/lib/queryBuilder/QueryBuilderOperationSupport.js:345:33)
      at QueryBuilder.addOperationUsingMethod (node_modules/objection/lib/queryBuilder/QueryBuilderOperationSupport.js:381:28)
      at QueryBuilder.addOperation (node_modules/objection/lib/queryBuilder/QueryBuilderOperationSupport.js:372:22)
      at writeOperation (node_modules/objection/lib/queryBuilder/QueryBuilder.js:890:12)
      at writeOperation (node_modules/objection/lib/queryBuilder/QueryBuilder.js:1465:5)

注意:我没有采用原始方法,但这只是最后的手段

编辑:为澄清起见,任何看起来都是假的都是因为它是,我从帖子中删除了大部分包袱(如模型属性和方法),如果需要,请告诉我。用户模式和候补名单模式都已完全开发且功能齐全,它们可以干净地用于 crud。我希望能够在给定等候名单、用户和目标排名的情况下修补连接表行

【问题讨论】:

【参考方案1】:

您的 json 架构必须包含 rank 属性,否则您需要允许其他属性或一起删除该虚拟架构。

http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.6

  static jsonSchema = 
    type: 'object',
    required: [],
    properties: ,
    additionalProperties: true
  

【讨论】:

这是对的,我认为不会为更改连接表的操作读取用户模式。即使用户自己没有排名,也可以将排名道具添加到架构中 我不知道该功能是否是故意的,但有点道理,因为在waitlists 模型中声明了额外的属性rank。还知道在哪个阶段完成 json 模式验证也很有意义。

以上是关于反对 js:无法使用连接表额外属性更新多对多关系。说附加属性无效的主要内容,如果未能解决你的问题,请参考以下文章

学说2:在多对多关系中引用连接表

通过联结表进行多对多自连接

EF更新多对多关系表中记录的时候,无法更新关系表的问题。

使用额外列映射多对多关联表

多对多关系 - 如何更新数据透视表中的属性

创建多对多表关系的三种方式