【问题标题】:Sequelize not returning instance of model续集不返回模型实例
【发布时间】:2017-01-24 18:28:23
【问题描述】:

续集文档 (http://docs.sequelizejs.com/en/v3/docs/raw-queries/) 指出:

如果您传递模型,则返回的数据将是该模型的实例。

// Callee is the model definition. This allows you to easily map a query to a predefined model
sequelize.query('SELECT * FROM projects', { model: Projects }).then(function(projects){
  // Each record will now be a instance of Project
})

我为名为@9​​87654324@ 的资源定义了一个模型。

module.exports = function(sequelize, DataTypes) {
   let Agent = sequelize.define('Agent', {
      responseStatus: DataTypes.STRING,
      agentnum: {
        type: DataTypes.STRING,
        primaryKey: true,
        allowNull: false,
        field : 'agentno'
      },
      fname :  {
        type: DataTypes.STRING,
        allowNull : false,
        field: 'fname'
      },
      lname : {
        type: DataTypes.STRING,
        allowNull: false,
        field : 'lname'
      }, 
      fullname : {
        type: DataTypes.STRING,
        allowNull : false,
        field: 'full_name'
      }, 
      status : {
        type: DataTypes.STRING,
        allowNull: false,
        field: 'business_status'
      }, 
      loginDate: DataTypes.DATE
  }, {
      freezeTableName: false,
      timestamps: false
  });

  return Agent;
};

当使用我的查询调用sequelize.query 并指定model:Agent 时,我收到sequelize 引发的错误:

TypeError: this.model.bulkBuild is not a function

堆栈指向sequelize\lib\dialects\abstract\query.js:675

此错误持续存在直到我应用了 sequelize.QueryTypes.RAW 的 QueryType。此时查询完成,我收到 JSON 响应,但它不是我的代理模型的实例。来自 sequelize 查询的 JSON 响应包含应映射到的字段名称。

我已经根据他们的快递样本 (https://github.com/sequelize/express-example/blob/master/models/index.js) 中的说明导入了我的模型(它只是一个)。模型集合显示包含我的代理模型。

import Sequelize from 'sequelize';
import config from './config';

export default callback => {
  const sequelize = new Sequelize(config.database, config.username, config.password, config.params);

  sequelize.sync().then(function() {
    let db = { }

    let agentModel = sequelize.import('model/agent.js');
    db[agentModel.name] = agentModel;

    db.sequelize = sequelize;
    db.Sequelize = Sequelize;

    db.sequelize.authenticate().then(function() {
      console.log('CONNECTION OK');
    });


    callback(db);

  }).catch(function(err) {
    console.log('FAILED TO CONNECT: ', err.message);
  });
}

我希望查询在运行该查询时返回一个代理实例(从 POST 调用到我的 api)。我正在使用 MS SQL Server 2008 R2。

感谢任何输入。谢谢。

EDIT 1/30 这是生成sequelize 对象并传入模型的代码。模型集合显示我的项目已添加,但它没有属性。

connectDb: (function () {
        var sequelize;
        function createInstance() {
            var sequelizeInstance, connectedAndAuthenticated;
            sequelizeInstance = new Sequelize(config.database, config.username, config.password, config.params);
            connectedAndAuthenticated = sequelizeInstance.authenticate();
            connectedAndAuthenticated.sequelize = sequelizeInstance;
            connectedAndAuthenticated.Sequelize = Sequelize;

            var model = sequelizeInstance.import('../src/model/agent.js');


            return connectedAndAuthenticated;
        }
        return {
            getInstance : function () {
                if (!sequelize) {
                    sequelize = createInstance();
                }
                return sequelize;
            }
        };
    }())

EDIT 1/26 在操作QueryTypes 之后,我发现了两件事——我无意中在数据库中创建了一个名称为模型(Agent)的表,并且该对象返回tablename 属性值为空。 schematablename 是我指定的,但查询是一个连接多个查询和表的存储过程,不会直接映射到我的数据库中名为 Agent 的对象。话虽如此,对我来说,文档似乎表明 这并不重要,因为我正在创建自己的模型,该模型绑定到查询结果。

【问题讨论】:

  • 您的查询是什么?
  • db.sequelize .query( "DECLARE @response VARCHAR(256); EXEC API_Login @agentnum = N'" + agentNum + "', @hashedPassword = '" + password + "', @response = @response OUTPUT; SELECT @response AS N'response'",{ model: Agent, type: sequelize.QueryTypes.RAW}) .spread(function(Agent) { res.status(200).json(Agent); }) .catch(function(err) { handleError(err, res); }); - 这是一个被调用的存储过程。
  • 如果你做type: sequelize.QueryTypes.SELECT怎么办?
  • @Adam 每个其他 QueryType 要么失败,要么在响应中不返回任何内容。

标签: javascript express sequelize.js


【解决方案1】:

sequelize doc 令人困惑。我正在向您解释使用 sequelize 的干净方式 放

var models = require('../models');

在您的代码文件中,确保模型目录包含您在问题中告诉我的 index.js 以及项目模型。 小心,除了正确配置的模型之外,不能有任何东西。 现在放

 models.sequelize.query("select 1 as val").then(function(result){
console.log(result)
})

在您的代码中 要检查连接,您还应该使用类似

的查找查询
 models.Projects.findAll().then(function(result){
    console.log(result)
    })

【讨论】:

  • 是的,它令人困惑!但这不是一个可以接受的答案。我能够连接到现有的 SQL Server 实例,并且能够对其进行查询。我似乎无法弄清楚或做的是将我现有的模型(位于模型目录中)绑定到存储过程的输出,即使文档似乎表明这可以通过传入模型的名称来实现。
  • 数据会自动与模型名称的模型调用绑定。我不明白你在混淆什么。但我认为您正在寻找类、getter 和 setter 方法来在存储或检索时操作数据
  • “数据会自动与模型名称调用绑定”——我的意思是我已经做到了。我已经尝试手动将模型添加到模型集合以及在查询中指定模型,但它不会自动绑定。当我检查集合时,模型被加载。相反,它只返回查询结果。这不是一个发现——我在文档中读到的想法是您只需定义您的模型,当您查询时它将绑定到提供的模型。它现在不这样做。我误解了文档吗?
  • models 目录中的index.js 文件似乎是一个加载器。我在创建数据库对象时尝试加载模型。它只是一个模型。如果我将对象内容记录到控制台(它输出对象名称),我可以看到它已添加到集合中。但它没有属性。请参阅上面的更新代码。
  • 补充一点,我已经同步了模型——查询尝试创建一个表,而不是绑定到传入的代理模型。我知道这一点,因为当我执行此测试时,控制台中会引发异常:“未处理的拒绝 SequelizeDatabaseError:数据库“代理”中的 CREATE TABLE 权限被拒绝。”它不应该创建一个表 - 这是一个执行 SELECT 的存储过程
【解决方案2】:

这似乎是一个简单的错字。我不认为 Agent 实际上是在您的范围内定义的。我认为您应该传递 agentModel 或您绑定导入的任何内容。

let agentModel = sequelize.import('model/agent.js');    
db.sequelize.query( "DECLARE @response VARCHAR(256); EXEC API_Login @agentnum = N'" + agentNum + "', @hashedPassword = '" + password + "', @response = @response OUTPUT; SELECT @response AS N'response'",{ model: agentModel, type: sequelize.QueryTypes.RAW}) .spread(function(Agent) { res.status(200).json(Agent); }) .catch(function(err) { handleError(err, res); });

请注意,我使用的是{model: agentModel, ...} 而不是{model: Agent, ...},因为Agent 在回调之外是未定义的。

如果Agent 实际上不是模型而是其他东西(或未定义),那么您的错误TypeError: this.model.bulkBuild is not a function 就完全合理。

更新

您在下面帖子的 cmets 中提到:“我已同步模型 - 查询尝试创建表,而不是绑定到传入的代理模型”和“它不应该创建表”。

你为什么会这样认为?在 sync() 期间创建表是 Sequelize 的正常行为

我认为您误解了 Sequelize 的工作原理。它在同步期间为每个注册的模型创建一个表。如果它无法创建该表,则可能会返回无效模型,这就是您收到错误的原因。

模型明确地绑定到各个数据库表,这是 Sequelize 的基本行为。每个模型实例代表该表的一行。如果您正在使用存储过程,那么您最好使用本机数据库库并定义自己的抽象层。

我确信您可以禁用和/或覆盖模型和基础数据库表之间的所有默认同步,但是在某个点或复杂性上,您基本上只是编写了自己的抽象库,这样会更干净只需从头开始。

也许你可以按照你想要的方式使用 Sequelize,但至少你不应该打电话给 sync()。导致什么副作用我不能说,但我可以说除非你定义自己的 beforeSync 钩子 sync() 将始终在你的架构中创建一个表:

Model.prototype.sync = function(options) {
  options = options || {};
  options.hooks = options.hooks === undefined ? true : !!options.hooks;
  options = Utils._.extend({}, this.options, options);

  var self = this
    , attributes = this.tableAttributes;

  return Promise.try(function () {
    if (options.hooks) {
      return self.runHooks('beforeSync', options);
    }
  }).then(function () {
    if (options.force) {
      return self.drop(options);
    }
  }).then(function () {
    return self.QueryInterface.createTable(self.getTableName(options), attributes, options, self);
  })
  ...
  }).return(this);
};

【讨论】:

  • 错误仍然存​​在。我应该澄清一下我之前确实尝试过这个。起初我理解这是集合中模型的名称(它被定义为“代理”,所以我认为 JSON 想要定义模型的名称,而不是实例),但是当我更改它时,我得到了相同的除 Raw 之外的所有其他查询类型都出现异常,它返回原始 json。
  • 你试过 console.debug(agentModel) 看看它到底是什么吗?它有一个 bulkBuild 方法吗?此外,如果库真的想要代理的 name (我不相信它确实如此),那么那将是字符串 "Agent" 而不是变量 Agent (可能是未定义的)
  • 是的。它是一个 JSON 对象,如下所示:{ Agent : Agent }。没有为其分配任何属性。它正在加载模型文件,因为如果我故意弄错路径,应用程序会抛出异常,否则我注意到的就是这些。
  • 我明白你在说什么,但我最初引用的文档似乎表明,如果我想将查询绑定到已经存在的模型,我可以通过将模型应用于它来实现。在这种情况下,我希望查询字段映射到我指定的字段名,但这并没有发生。请参阅stackoverflow.com/questions/39435291/…,其中另一位 SO 成员遇到了类似问题(此处未发布解决方案)
  • 这并没有澄清我的主要问题。你知道Agent到底是什么吗?如何在运行查询的范围内定义变量 Agent?在您发布的代码中Agentundefined
猜你喜欢
  • 2021-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-06
  • 2018-01-18
  • 1970-01-01
相关资源
最近更新 更多