应用"getter"获取器应该出了一些问题. model-builder.js中的方法 [英] Something should be wrong with applying of "getter" methods in model-builder.js

查看:85
本文介绍了应用"getter"获取器应该出了一些问题. model-builder.js中的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试设置一些基本方案,并使用LoopBack来了解其实际的灵活性和可用性.

其中之一是在处理db(例如MySQL)的源数据期间,必须修改结果JSON objetcs中某些属性的值.

我正在使用以下版本:

strong-cli v2.5.5(节点v0.10.29) 节点检查器v0.7.4 强大的构建v0.1.0 强集群控制v0.4.0 强大注册表v1.1.0 strong-supervisor v0.2.3(强代理v0.4.9,strong-cluster-control v0.4.0) loopback-datasource-juggler v1.6.2 loopback-connector-mysql v1.4.1

我尝试了所有方法,但看起来"getter"方法是我不理解或有错误的方式所应用的.

为了描述这个问题,我使用了一个简单的表"city"(在MySQL数据库中):

CREATE TABLE `city` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `countryId` bigint(20) NOT NULL,
  `name` varchar(100) NOT NULL,
  `comment` varchar(255) DEFAULT NULL,
  `enabled` char(1) NOT NULL DEFAULT 'Y',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`)
)

并填写了一些简单的数据.

要在LoopBack中定义模型,我使用了位于模型"目录中的文件"city.js":

"use strict";

var loopback = require('loopback');
var app = require('../app.js');

var properties = {
    id: {type: "number", id: true},
    countryId: {type: "number"},
    name: {type: "string"},
    comment: {type: "string"},
    enabled: {type: "string"}
};

var options = {
    acls: [
        {
            accessType: "*",
            permission: "ALLOW",
            principalType: "ROLE",
            principalId: "$everyone"
        }
    ]
};

var City = app.model("city", {
    properties: properties, 
    options: options,
    public: true,
    dataSource: "mysql",
    plural: "cities"
});

City.getter["enabled"] = function(v) {
    console.log("Getter is called: ", v);
    return 'Q'
};

如您所见,"getter"方法是使用"City"对象在"city"模型上定义的.

当我尝试运行LoopBack并通过StrongLoop API Explorer发送请求时:

http://localhost:3000/api/cities/1

控制台看起来像(包括DEBUG = loopback:connector:*的信息):

supervisor running without clustering (unsupervised)
loopback:connector:mysql Settings: {"connector":"loopback-connector-mysql","host":...
connect.multipart() will be removed in connect 3.0
visit https://github.com/senchalabs/connect/wiki/Connect-3.0 for alternatives
connect.limit() will be removed in connect 3.0
Getter is called:  undefined
Getter is called:  undefined
2014-07-12T12:26:41.978Z pid:12180 worker:supervisor INFO strong-agent not profiling, ...
2014-07-12T12:26:41.981Z pid:12180 worker:supervisor Generate configuration with:
2014-07-12T12:26:41.983Z pid:12180 worker:supervisor     npm install -g strong-cli
2014-07-12T12:26:41.983Z pid:12180 worker:supervisor     slc strongops
2014-07-12T12:26:41.983Z pid:12180 worker:supervisor See http://docs.strongloop.com/...
Browse your REST API at ...
LoopBack server listening @ ...
Getter is called:  undefined
  loopback:connector:mysql SQL: SELECT * FROM `city` WHERE `id` = 1 LIMIT 1 +8s
  loopback:connector:mysql Data:  +9ms [ { id: 1,
    countryId: 1,
    name: 'Brno',
    comment: 'The second largest city of its country',
    enabled: 'Y' } ]
Getter is called:  undefined
GET /api/cities/1 304 44ms

结果如下:

{
  "id": 1,
  "countryId": 1,
  "name": "Brno",
  "comment": "The second largest city of its country",
  "enabled": "Q"
}

如您所见,"enabled"属性最终通过"getter"方法更改,但是:

  • 'getter'方法在LoopBack初始化期间也称为2x
  • 在查询MySQL db之前,
  • 'getter'方法也被称为1x
  • "getter"方法中的
  • console.log(v)始终返回未定义"

loopback-datasource-juggler中的"model-builder.js"的源代码(第364行)

Object.defineProperty(ModelClass.prototype, propertyName, {
  get: function () {
    if (ModelClass.getter[propertyName]) {
      return ModelClass.getter[propertyName].call(this); // Try getter first
    } else {
      return this.__data && this.__data[propertyName]; // Try __data
    }
  },

解释原因. 调用"方法只有一个参数(this)表示被调用函数中的"this"对象,没有第二个参数表示被调用函数中的参数"v"(与Raymond Feng关于如何创建getter和setter替代?).). >

问题还在于,"getter"方法中的"this"始终表示包含模型所有属性的对象:

City.getter["enabled"] = function(v) {
    console.log("Getter is called: ", this);
    return 'Q'
};

,然后从控制台发送消息:

Getter is called: { id: 1, countryId: 1, name: 'Brno', comment: 'The second largest city of its country', enabled: 'Y' }

能否请您解释一下当前实现"getter"方法的想法?

非常感谢.

米洛斯·拉皮斯(Milos Lapis) MLC

更新

非常感谢Raymond的回答.

起初我以为是这样,但是当我使用类似的东西时:

City.getter["enabled"] = function() {
    return this.enabled + "x"
};

当我请求时,节点立即崩溃:

localhost:3000/api/cities/1

出现错误:RangeError:超出了最大调用堆栈大小

这就是为什么我认为您的实现有所不同的原因.有什么问题吗?

我到底应该使用什么来将'x'添加到从数据库检索到的实际值中?

谢谢.

米洛斯·拉皮斯(Milos Lapis) MLC

解决方案

在示例代码中,您将递归调用已定义的getter.

City.getter["enabled"] = function() {
  // this.enabled calls City.getter["enabled"]
  return this.enabled + "x"
};

从数据库中检索到的值存储在__data属性中.这是更正后的吸气功能:

City.getter["enabled"] = function() {
  return this.__data.enabled + "x"
};

I am trying to set-up some basic scenarios and use LoopBack to find out its actual level of flexibility and usability.

One of them is the necessity to modify the value of some attributes in resulted JSON objetcs during processing the source data from a db (e.g. MySQL).

I am using the following versions:

strong-cli v2.5.5 (node v0.10.29) node-inspector v0.7.4 strong-build v0.1.0 strong-cluster-control v0.4.0 strong-registry v1.1.0 strong-supervisor v0.2.3 (strong-agent v0.4.9, strong-cluster-control v0.4.0) loopback-datasource-juggler v1.6.2 loopback-connector-mysql v1.4.1

I tried everything but it looks that "getter" method is applied by the way I don't understand or there is a bug.

To describe the problem I used a simple table "city" (in MySQL db):

CREATE TABLE `city` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `countryId` bigint(20) NOT NULL,
  `name` varchar(100) NOT NULL,
  `comment` varchar(255) DEFAULT NULL,
  `enabled` char(1) NOT NULL DEFAULT 'Y',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`)
)

and filled some simple data.

To define the model in LoopBack I used the file "city.js" located in "models" directory:

"use strict";

var loopback = require('loopback');
var app = require('../app.js');

var properties = {
    id: {type: "number", id: true},
    countryId: {type: "number"},
    name: {type: "string"},
    comment: {type: "string"},
    enabled: {type: "string"}
};

var options = {
    acls: [
        {
            accessType: "*",
            permission: "ALLOW",
            principalType: "ROLE",
            principalId: "$everyone"
        }
    ]
};

var City = app.model("city", {
    properties: properties, 
    options: options,
    public: true,
    dataSource: "mysql",
    plural: "cities"
});

City.getter["enabled"] = function(v) {
    console.log("Getter is called: ", v);
    return 'Q'
};

As you can see the "getter" method is defined on "city" model using "City" object.

When I try to run LoopBack and then send a request through StrongLoop API Explorer:

http://localhost:3000/api/cities/1

the console looks like (icluding info for DEBUG=loopback:connector:*):

supervisor running without clustering (unsupervised)
loopback:connector:mysql Settings: {"connector":"loopback-connector-mysql","host":...
connect.multipart() will be removed in connect 3.0
visit https://github.com/senchalabs/connect/wiki/Connect-3.0 for alternatives
connect.limit() will be removed in connect 3.0
Getter is called:  undefined
Getter is called:  undefined
2014-07-12T12:26:41.978Z pid:12180 worker:supervisor INFO strong-agent not profiling, ...
2014-07-12T12:26:41.981Z pid:12180 worker:supervisor Generate configuration with:
2014-07-12T12:26:41.983Z pid:12180 worker:supervisor     npm install -g strong-cli
2014-07-12T12:26:41.983Z pid:12180 worker:supervisor     slc strongops
2014-07-12T12:26:41.983Z pid:12180 worker:supervisor See http://docs.strongloop.com/...
Browse your REST API at ...
LoopBack server listening @ ...
Getter is called:  undefined
  loopback:connector:mysql SQL: SELECT * FROM `city` WHERE `id` = 1 LIMIT 1 +8s
  loopback:connector:mysql Data:  +9ms [ { id: 1,
    countryId: 1,
    name: 'Brno',
    comment: 'The second largest city of its country',
    enabled: 'Y' } ]
Getter is called:  undefined
GET /api/cities/1 304 44ms

and the result looks like:

{
  "id": 1,
  "countryId": 1,
  "name": "Brno",
  "comment": "The second largest city of its country",
  "enabled": "Q"
}

As you can see the "enabled" attribute is finally changed by "getter" method but:

  • 'getter' method is also called 2x during initialization of LoopBack
  • 'getter' method is also called 1x immediately before MySQL db is queried
  • console.log(v) inside 'getter' method always returns 'undefined'

The source code of 'model-builder.js' in loopback-datasource-juggler (line 364)

Object.defineProperty(ModelClass.prototype, propertyName, {
  get: function () {
    if (ModelClass.getter[propertyName]) {
      return ModelClass.getter[propertyName].call(this); // Try getter first
    } else {
      return this.__data && this.__data[propertyName]; // Try __data
    }
  },

is an explanation why. The 'call' method has only one parameter (this) which represent 'this' object in the called function and there is no second parameter which would represent the parameter 'v' in the called function (related to the answer of Raymond Feng on How do I create getter and setter overrides?).

The problem is also that 'this' inside 'getter' method always represents an object that include all properties of the model:

City.getter["enabled"] = function(v) {
    console.log("Getter is called: ", this);
    return 'Q'
};

and the message from console then:

Getter is called: { id: 1, countryId: 1, name: 'Brno', comment: 'The second largest city of its country', enabled: 'Y' }

Can you explain me the idea of the current implementation of "getter" methods please?

Thanks a lot.

Milos Lapis MLC

UPDATE

Thanks a lot Raymond for your answer.

At the very first I supposed that but when I used something like:

City.getter["enabled"] = function() {
    return this.enabled + "x"
};

the Node crashed immediately when I requested:

localhost:3000/api/cities/1

with an error: RangeError: Maximum call stack size exceeded

That is why I thought that your implementation is a bit different. Is there something wrong?

What exactly should I use to add 'x' to the actual value retrieved from db?

Thanks.

Milos Lapis MLC

解决方案

In your example code, you are recursively calling the getter you have defined.

City.getter["enabled"] = function() {
  // this.enabled calls City.getter["enabled"]
  return this.enabled + "x"
};

The value retrieved from DB is stored in __data property. Here is the corrected getter function:

City.getter["enabled"] = function() {
  return this.__data.enabled + "x"
};

这篇关于应用"getter"获取器应该出了一些问题. model-builder.js中的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆