Loopbackjs 环回设置一个属性,该属性以某种方式不';不能持久化到数据库sql?

Loopbackjs 环回设置一个属性,该属性以某种方式不';不能持久化到数据库sql?,loopbackjs,Loopbackjs,我们正在将api从C#移植到Loopback^v3.19.0,并且遇到了一个拦截器 我们的许多模型都具有共享属性,因此我们创建了一个基础模型“base”,它们从中继承 { "name": "Base", "base": "PersistedModel", "idInjection": true, "options": { "validateUpsert": true }, "mixins": { "Timestamp": {} }, "proper

我们正在将api从C#移植到Loopback
^v3.19.0
,并且遇到了一个拦截器

我们的许多模型都具有共享属性,因此我们创建了一个基础模型“base”,它们从中继承

{
  "name": "Base",
  "base": "PersistedModel",
  "idInjection": true,
  "options": {
    "validateUpsert": true
  },
  "mixins": {
    "Timestamp": {}
  },
  "properties": {   
    "created-by": {
      "type": "number",
      "postgresql": {
        "columnName": "created_by"
      }
    },
    "created-date": {
      "type": "date",
      "postgresql": {
        "columnName": "created_on_utc"
      }
    },
    "updated-by": {
      "type": "number",
      "postgresql": {
        "columnName": "updated_by"
      }
    },
    "updated-date": {
      "type": "date",
      "postgresql": {
        "columnName": "updated_on_utc"
      }
    },
    "soft-deleted": {
      "type": "boolean",
      "postgresql": {
        "columnName": "is_deleted"
      }
    },
    "deleted-by": {
      "type": "number",
      "postgresql": {
        "columnName": "deleted_by"
      }
    },
    "deleted-date": {
      "type": "date",
      "postgresql": {
        "columnName": "deleted_on_utc"
      }
    },
    "tenant-id": {
      "type": "number",
      "postgresql": {
        "columnName": "tenant_id"
      }
    }
  },
  ...
}
时间戳mixin(我们自己的)中,相应地设置这些属性

module.exports = function(Model, options) {
  Model.observe('before save', function event(ctx, next) {
    const token = ctx.options && ctx.options.accessToken;
    const userId = token && token.userId;
    const now = new Date().toISOString();

    if (ctx.instance) {
      ctx.instance['created-by'] = userId;
      ctx.instance['created-date'] = now;
      ctx.instance['updated-by'] = userId;
      ctx.instance['updated-date'] = now;
    } else {
      if (ctx.data['soft-deleted'] &&
          ctx.data['soft-deleted'] === true) {
        ctx.data['deleted-by'] = userId;
        ctx.data['deleted-date'] = now;
        ctx.data['is-active'] = false;
      }
      ctx.data['updated-by'] = userId;
      ctx.data['updated-date'] = now;
    }

    next();
  });
};
这在创建新模型时非常有效。对于更新
(PATCH/modelname/:id)
,它工作得很好,但意外地坏了,我们无法找出原因。(这在继承自此
Base
模型的所有模型中都是一致的。)

mixin可以正确地看到模型并添加更新的属性,如下所示

LoopbackJS  | ************* 'before save' ctx.data **************
LoopbackJS  | { 'is-active': false,
LoopbackJS  |   'updated-by': 1,
LoopbackJS  |   'updated-date': '2018-08-16T17:57:23.660Z' }
LoopbackJS  | ************* END 'before save' ctx.data **************
但是,当环回执行更新SQL时,它会以某种方式忽略/删除由更新的
的值?(第二个参数应该是
1
,而不是
null

Postgres中由
更新的
可为空,因此不应生成错误。。。但是环回发送的是一个字符串化的函数吗

LoopbackJS  | 2018-08-16T18:04:12.522Z loopback:connector:postgresql error: invalid input syntax for integer: "function () { [native code] }"
LoopbackJS  |     at Connection.parseE (/home/src/back-end/node_modules/pg/lib/connection.js:553:11)
LoopbackJS  |     at Connection.parseMessage (/home/src/back-end/node_modules/pg/lib/connection.js:378:19)
LoopbackJS  |     at TLSSocket.<anonymous> (/home/src/back-end/node_modules/pg/lib/connection.js:119:22)
LoopbackJS  |     at emitOne (events.js:115:13)
LoopbackJS  |     at TLSSocket.emit (events.js:210:7)
LoopbackJS  |     at addChunk (_stream_readable.js:264:12)
LoopbackJS  |     at readableAddChunk (_stream_readable.js:251:11)
LoopbackJS  |     at TLSSocket.Readable.push (_stream_readable.js:209:10)
LoopbackJS  |     at TLSWrap.onread (net.js:587:20)
LoopbackJS | 2018-08-16T18:04:12.522Z环回:连接器:postgresql错误:整数的输入语法无效:“函数(){[本机代码]}”
LoopbackJS| at Connection.parseE(/home/src/back-end/node_modules/pg/lib/Connection.js:553:11)
LoopbackJS | at Connection.parseMessage(/home/src/back-end/node_modules/pg/lib/Connection.js:378:19)
TLSSocket处的环回JS |。(/home/src/back-end/node_modules/pg/lib/connection.js:119:22)
emitOne上的LoopbackJS(events.js:115:13)
LoopbackJS |位于TLSSocket.emit(events.js:210:7)
LoopbackJS|位于addChunk(_stream_readable.js:264:12)
LoopbackJS | at readableAddChunk(_stream_readable.js:251:11)
LoopbackJS |位于TLSSocket.Readable.push(_stream_Readable.js:209:10)
LoopbackJS |位于TLSWrap.onread(net.js:587:20)
如果我们不点击
updated\u by
列,则SQL是正确的,并且会更新

顺便说一句,如果我们软删除并且
deleted\u by
列正在运行,同样的事情也会发生

感觉就像我在绕圈子,可能忽略了一些基本的东西。有什么建议吗

编辑


所以它似乎并不局限于一个混合。。。当我们完全删除它并手动设置有效负载中的k:v对(即“创建人”:1)时,我们仍然从Postgres返回相同的错误。

这一错误的根本原因是由于不正确的关系

我创建了这个,但也将它粘贴在这里,以防它对其他人有帮助

使用小写名称是PostgreSQL的最佳实践,如果需要,可以使用snakecase。我的名字

另外,由于我使用的是客户机,所以我安装了优秀的来处理反序列化内容。。。但这只会增加额外的复杂性

JSON API调用dasherized属性名。当您以类似于
my property name
的内容开始时,默认情况下,环回或PostgreSQL驱动程序(其实并不重要)会将dasherized属性向下折叠为
mypropertyname

这很糟糕。。。尤其是当您有一个正在使用的现有模式时

处理关系时情况更糟,因为默认情况下,环回还会附加
id
后缀,所以现在您会遇到问题,除非您碰巧有
mypropertynameid

一个例子 假设我们有一个
客户
模型。我需要小写的端点(并且在适用的情况下使用dasherised),所以只需将复数形式更改为与此处匹配即可

{ 
  "name": "Customer",
  "plural": "customers",
  "base": "PersistedModel",
   ...
 }
选项.postgresql
中,可以设置
表名
。默认情况下,环回将使用
名称
值,但请记住PostgreSQL不喜欢CamelCase。除非使用小写的模型名称,否则需要重写此选项

(这是一种宗教偏好,但我喜欢我的桌子是复数的。跟我打吧。)

回到属性,使用
postgresql.columnName
属性映射到数据库中正确的列名。如果它不是dasherized属性名(即
status
),则可以忽略
postgresql.columnName

{ 
  ...
  "properties": {
    "is-active": {
      "type": "boolean",
      "default": false,
      "postgresql": {
        "columnName": "is_active"
      }
    }
  }
}
人际关系可能令人头痛。

假设我们的
客户
有人在那里工作。要做一个基本的一个多个模型之间的关系

{ 
  ...
  "relations": {
    "people": {
      "type": "hasMany",
      "model": "Person",
      "foreignKey": "customer_id"
    }
  },
  ...
}
people
是JSON API负载的relationship元素的名称

对我来说,这里的“抓到”是
foreignKey
属性。

循环文档说它是可选的,而且是-但是如果您不使用它,它会将
id
后缀添加到名称(
person
),然后在
customers
表中查找该列。这并没有很好地突出显示,但已经足够清楚了

这部分不清楚=>我最初认为
foreignKey
值指向
Person
模型的属性,因此我在这里使用了dasherised
客户id
属性这是不正确的。它实际上是在询问数据库列名,这感觉有点像反模式。。。如果要引用ORM下的db列,则必须在属性中定义一个
columnName

另外,请注意,
foreignKey
属性在关系中重用,但它对不同的
类型
上下文意味着不同的内容。在一个
hasMany
中,它询问“此处哪个列映射到主键?”

最终
客户
型号:
{ 
  "name": "Customer",
  "plural": "customers",
  "base": "PersistedModel",
  "options": {
    "validateUpsert": true,
    "postgresql": {
      "tableName": "customers"
    }
  },
  "properties": {
    "name": {
      "type": "string"
    },
    "is-active": {
      "type": "boolean",
      "default": false,
      "postgresql": {
        "columnName": "is_active"
      }
    }
  },
  "validations": [],
  "relations": {
    "people": {
      "type": "hasMany",
      "model": "Person",
      "foreignKey": "customer_id"
    }
  },
  "acls": [],
  "methods": {}
}
关系另一端的
Person
模型

belongsTo
关系的
foreignKey
提出了相反的问题。。。“此处的哪个属性映射到此处的主键?”

此外,如果您有不希望公开的属性(特别是如果您继承了一个模型,并且不希望/不需要w的所有这些属性)
{ 
  ...
  "relations": {
    "people": {
      "type": "hasMany",
      "model": "Person",
      "foreignKey": "customer_id"
    }
  },
  ...
}
{ 
  "name": "Customer",
  "plural": "customers",
  "base": "PersistedModel",
  "options": {
    "validateUpsert": true,
    "postgresql": {
      "tableName": "customers"
    }
  },
  "properties": {
    "name": {
      "type": "string"
    },
    "is-active": {
      "type": "boolean",
      "default": false,
      "postgresql": {
        "columnName": "is_active"
      }
    }
  },
  "validations": [],
  "relations": {
    "people": {
      "type": "hasMany",
      "model": "Person",
      "foreignKey": "customer_id"
    }
  },
  "acls": [],
  "methods": {}
}
{
  "name": "Person",
  "plural": "people",
  "base": "User",
  "idInjection": false,
  "options": {
    "validateUpsert": true,
    "postgresql": {
      "tableName": "people"
    }
  },
  "hidden": [
    "emailVerified",
    "realm",
    "username",
  ],
  "properties": {
    "first-name": {
      "type": "string",
      "postgresql": {
        "columnName": "first_name"
      }
    },
    "last-name": {
      "type": "string",
      "postgresql": {
        "columnName": "last_name"
      }
    },
    "email": {
      "type": "string"
    },
    ...
  },
  "validations": [],
  "relations": {
    "customer": {
      "type": "belongsTo",
      "model": "Customer",
      "foreignKey": "customer_id"
    }
  },
  "acls": [],
  "methods": {}
}