SequelizeEagerLoadingError: (parent) не связан с (child)! - PullRequest
1 голос
/ 15 марта 2019

Я создаю приложение, используя sequelize. В настоящее время у меня есть 3 таблицы; Пользователь, Тур и Местоположение. Местоположение имеет отношение n: 1 с Туром. Тур имеет отношения n: 1 с пользователем.

Без привязки пользователя две другие таблицы работают нормально. Как только я добавляю ассоциацию пользователей (и я пытался сделать это путем миграции и удаления, а затем воссоздания всей базы данных), я получаю SequelizeEagerLoadingError: Местоположение не связано с Tour!

Вот мои модели:

module.exports = function(sequelize, DataTypes) {
  var Location = sequelize.define("Location", {
    title: {
      type: DataTypes.STRING,
      allowNull: false
    },
    description: {
      type: DataTypes.TEXT,
      allowNull: false,
      validate: {
        len: [500]
      }
    },
    address: {
      type: DataTypes.TEXT,
      allowNull: false
    }
  });

  Location.associate = function(models) {
    Location.belongsTo(models.Tour, {
      onDelete: "cascade"
    });
  };

  return Location;
};

module.exports = function(sequelize, DataTypes) {
  var Tour = sequelize.define("Tour", {
    title: {
      type: DataTypes.STRING,
      allowNull: false
        },
    description: {
      type: DataTypes.TEXT,
      allowNull: false,
      validate: {
        len: [1, 1000]
      }
    },
    neighborhood: {
      type: DataTypes.STRING,
      allowNull: false
    },
    URL: {
      type: DataTypes.TEXT,
      allowNull: false,
      validate: {
        len: [1, 1000]
      }
    },
    numberOfStops: DataTypes.INTEGER,
    duration: {
      type: DataTypes.INTEGER,
      allowNull: false
    },
    tags: DataTypes.STRING
  });

    Tour.associate = function(models) {
    Tour.hasMany(models.Location);
  };

  Tour.associate = function(models) {
    Tour.belongsTo(models.User);
  };

  return Tour;
};
 

var bcrypt = require("bcrypt-nodejs");
module.exports = function(sequelize, DataTypes) {
  var User = sequelize.define("User", {
    name: {
      type: DataTypes.STRING,
      allowNull: false
    },
    email: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true,
      validate: {
        isEmail: true
      }
    },
    password: {
      type: DataTypes.STRING,
      allowNull: false
    }
  });
  User.prototype.validPassword = function(password) {
    return bcrypt.compareSync(password, this.password);
  };

  User.hook("beforeCreate", function(user) {
    user.password = bcrypt.hashSync(
      user.password,
      bcrypt.genSaltSync(10),
      null
    );
  });

  User.associate = function(models) {
    User.hasMany(models.Tour);
  };

  return User;
};

А вот оператор включения, где он терпит неудачу, и где мы устанавливаем связь с tourId к местоположению:

app.get("/tour/:id", function(req, res) {
    db.Tour.findOne({
      where: { id: req.params.id },
      include: [db.Location]
    }).then(function(tour) {
      res.render("tour", {
        tour: tour
      });
    });
  });
  
  
  
  
   

var API = {
  saveTour: function(tour) {
    return $.ajax({
      headers: {
        "Content-Type": "application/json"
      },
      type: "POST",
      url: "api/tours",
      data: JSON.stringify(tour)
    });
  },
  saveLocations: function(locations) {
    return $.ajax({
      headers: {
        "Content-Type": "application/json"
      },
      type: "POST",
      url: "api/locations",
      data: JSON.stringify(locations)
    });
  },
  getUserId: function() {
    return $.ajax({
      type: "GET",
      url: "api/user_data"
    });
  }
};

var tour = {
    Users: thisUser.getUserId(),
    title: title,
    description: description,
    neighborhood: neighborhood,
    URL: URL,
    duration: duration,
    tags: tags
  };

  // console.log(tour);

  if (!errors.length) {
    // Post our tour to the Tours table, then reveal the form and set our local tour object.
    API.saveTour(tour).then(function(tour) {
      document.getElementById("submit-tour").remove();
      document.getElementById("tourstopssection").style.display = "block";
      thisTour.setId(tour.id);
    });
  }
}

// Function takes in the newly created tour object, grabs DOM values for each.
function addTourLocations(e) {
  e.preventDefault();
  // Grab and process all of our tour stops.
  var locationElements = document.getElementsByClassName("tourstop");
  var areStopErrors = false;
  var locations = [];

  // Loop over every location element on the DOM.
  for (var j = 0; j < locationElements.length; j++) {
    var children = locationElements[j].children;

    // Initialize this location with the tour id; we'll pass in data...
    var thisLocation = {
      TourId: thisTour.getId()
    };

    // ... by looping over the DOM children and grabbing their form values.
    for (var k = 0; k < children.length; k++) {
      if (
        children[k].classList.value.includes("stoptitle") &&
        children[k].value
      ) {
        var stopTitle = children[k].value;
        thisLocation.title = stopTitle;
      }

      if (
        children[k].classList.value.includes("stopaddress") &&
        children[k].value
      ) {
        var stopAddress = children[k].value;
        thisLocation.address = stopAddress;
      }

      if (
        children[k].classList.value.includes("stopdescription") &&
        children[k].value
      ) {
        var stopDescription = children[k].value;
        thisLocation.description = stopDescription;
      }
    }

    // Push this location into our locations array.
    locations.push(thisLocation);

Наконец, вот как синхронизируются app / db:

require("dotenv").config();
var express = require("express");
var session = require("express-session");
var exphbs = require("express-handlebars");
var helpers = require("./lib/helpers");

var db = require("./models");
var passport = require("./config/passport");

var app = express();
var PORT = process.env.PORT || 3000;

// Middleware
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static("public"));

var hbs = exphbs.create({
  defaultLayout: "main",
  helpers: helpers // Require our custom Handlebars helpers.
});

//Sessions are used to keep track of our user's login status
app.use(
  session({ secret: "keyboard cat", resave: true, saveUninitialized: true })
);
app.use(passport.initialize());
app.use(passport.session());
app.use(function(req, res, next) {
  res.locals.user = req.user; // Set a local variable for our user.
  next();
});

// Handlebars
app.engine("handlebars", hbs.engine);
app.set("view engine", "handlebars");

// Routes
require("./routes/apiRoutes")(app);
require("./routes/htmlRoutes")(app);

var syncOptions = { force: false };

// If running a test, set syncOptions.force to true
// clearing the `testdb`
if (process.env.NODE_ENV === "test") {
  syncOptions.force = true;
}

// Starting the server, syncing our models ------------------------------------/
db.sequelize.sync(syncOptions).then(function() {
  app.listen(PORT, function() {
    console.log(
      "==> ?  Listening on port %s. Visit http://localhost:%s/ in your browser.",
      PORT,
      PORT
    );
  });
});

module.exports = app;

Я гуглил четыре дня .... помогите!

Ответы [ 2 ]

0 голосов
/ 16 марта 2019

Я понял это - тот факт, что я определил ассоциацию на модели туров дважды, разрушал все.Как только я объединил их, как уже упоминалось выше, все заработало отлично!

Еще одна вещь, на которую следует обратить внимание - sequelize автоматически назначает внешний ключ и псевдоним, поэтому я пропустил эту часть.

0 голосов
/ 15 марта 2019

Попробуйте добавить это к своим ассоциациям, а также почему вы дважды определяете функцию ассоциации в туре?

module.exports = function(sequelize, DataTypes) {
  var Location = sequelize.define("Location", {
    //
  });

  Location.associate = function(models) {
    Location.belongsTo(models.Tour, { as:'Tour', foreignKey:'tourId', onDelete: "cascade"});
  };

  return Location;
};

module.exports = function(sequelize, DataTypes) {
  var Tour = sequelize.define("Tour", {
    //
  });

  Tour.associate = function(models) {
    Tour.hasMany(models.Location, { as: 'Locations', foreignKey: 'tourId'});
    Tour.belongsTo(models.User, { as: 'User', foreignKey: 'userId' });
  };


  return Tour;
};

module.exports = function(sequelize, DataTypes) {
  var User = sequelize.define("User", {
    //
  });

  User.associate = function(models) {
    User.hasMany(models.Tour, {as: 'Tours', foreignKey: 'userId'});
  };

  return User;
};

И добавить то же самое в запрос.

db.Tour.findOne({
  where: { id: req.params.id },
  include: [{ 
    model: db.Location,
    as: 'Locations'
  }]
}).then(function(tour) {
  res.render("tour", {
    tour: tour
  });
});
...