├── .gitignore ├── README.md ├── app.js ├── bin └── www ├── model ├── _db.js ├── index.js ├── role.js ├── transaction.js ├── user.js ├── userAddress.js └── userCheckin.js ├── package.json ├── public └── css │ └── style.css ├── routes └── index.js └── views ├── error.ejs └── index.ejs /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /.idea/* 3 | /.idea/*/* 4 | 5 | 6 | # Logs 7 | logs 8 | *.log 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # node-waf configuration 25 | .lock-wscript 26 | 27 | # Compiled binary addons (http://nodejs.org/api/addons.html) 28 | build/Release 29 | 30 | # Dependency directory 31 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 32 | node_modules 33 | .DS_Store 34 | 35 | /tools/crons/*.log 36 | 37 | /db 38 | ./db 39 | /public/upload 40 | /tmp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sequlize_model_relation_demo 2 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var favicon = require('serve-favicon'); 4 | var logger = require('morgan'); 5 | var cookieParser = require('cookie-parser'); 6 | var bodyParser = require('body-parser'); 7 | 8 | var routes = require('./routes/index'); 9 | 10 | var app = express(); 11 | 12 | // view engine setup 13 | app.set('views', path.join(__dirname, 'views')); 14 | app.set('view engine', 'ejs'); 15 | 16 | // uncomment after placing your favicon in /public 17 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); 18 | app.use(logger('dev')); 19 | app.use(bodyParser.json()); 20 | app.use(bodyParser.urlencoded({ extended: false })); 21 | app.use(cookieParser()); 22 | app.use(express.static(path.join(__dirname, 'public'))); 23 | 24 | app.use('/', routes); 25 | 26 | // catch 404 and forward to error handler 27 | app.use(function(req, res, next) { 28 | var err = new Error('Not Found'); 29 | err.status = 404; 30 | next(err); 31 | }); 32 | 33 | // error handlers 34 | 35 | // development error handler 36 | // will print stacktrace 37 | if (app.get('env') === 'development') { 38 | app.use(function(err, req, res, next) { 39 | res.status(err.status || 500); 40 | res.render('error', { 41 | message: err.message, 42 | error: err 43 | }); 44 | }); 45 | } 46 | 47 | // production error handler 48 | // no stacktraces leaked to user 49 | app.use(function(err, req, res, next) { 50 | res.status(err.status || 500); 51 | res.render('error', { 52 | message: err.message, 53 | error: {} 54 | }); 55 | }); 56 | 57 | 58 | module.exports = app; 59 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('sequelize_model_relation:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /model/_db.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Sequelize = require('sequelize'); 4 | 5 | exports.sequelize = function () { 6 | return new Sequelize('modelTest', 'root', '111111', {host: 'localhost', port:3306, logging:console.log}); 7 | } 8 | -------------------------------------------------------------------------------- /model/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sequelize=require('./_db').sequelize(); 4 | var User = sequelize.import('./user.js'); 5 | var UserCheckin = sequelize.import('./userCheckin.js'); 6 | var UserAddress = sequelize.import('./userAddress.js'); 7 | var Role = sequelize.import('./role.js'); 8 | 9 | // 建立模型之间的关系 10 | User.hasOne(UserCheckin); 11 | UserCheckin.belongsTo(User); 12 | User.hasMany(UserAddress, {foreignKey:'user_id', targetKey:'id', as:'Address'}); 13 | User.belongsToMany(Role, {through: 'userRoles', as:'UserRoles'}); 14 | Role.belongsToMany(User, {through: 'userRoles', as:'UserRoles'}); 15 | 16 | // 同步模型到数据库中 17 | sequelize.sync(); 18 | 19 | exports.User = User; 20 | exports.UserCheckin = UserCheckin; 21 | exports.UserAddress = UserAddress; 22 | exports.Role = Role; -------------------------------------------------------------------------------- /model/role.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (sequelize, DataTypes) { 4 | return sequelize.define('Role', { 5 | id: { type: DataTypes.BIGINT(11), autoIncrement: true, primaryKey: true, unique: true, comment:'角色Id' }, 6 | roleName: { type: DataTypes.STRING, field: 'role_name', comment:'角色名' } 7 | }, 8 | { 9 | underscored: true, 10 | timestamps: false, 11 | freezeTableName: true, 12 | tableName: 'role', 13 | charset: 'utf8', 14 | collate: 'utf8_general_ci' 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /model/transaction.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Sequelize = require('sequelize'); 4 | var Transaction = require('sequelize').Transaction; 5 | 6 | var sequelize = new Sequelize('modelTest', 'root', '111111', {host: 'localhost', port:3306, logging:console.log}); 7 | var User = sequelize.import('./user.js'); 8 | var UserCheckin = sequelize.import('./userCheckin.js'); 9 | 10 | 11 | sequelize.transaction(function (t) { 12 | // 在事务中执行操作 13 | return User.create({username: 'itbilu.com', password: 'pwd', active: true}, {transaction:t}) 14 | .then(function(user){ 15 | return UserCheckin.create({userId: user.id, loginIp:'127.0.0.1'}, {transaction:t}) 16 | }); 17 | }).then(function (results){ 18 | /* 操作成功,事务会自动提交 */ 19 | }).catch(function(err){ 20 | /* 操作失败,事件会自动回滚 */ 21 | }); 22 | 23 | -------------------------------------------------------------------------------- /model/user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (sequelize, DataTypes) { 4 | return sequelize.define('User', { 5 | id:{type:DataTypes.BIGINT(11), autoIncrement:true, primaryKey : true, unique : true}, 6 | username: { type: DataTypes.STRING, allowNull: false, comment:'用户名' }, 7 | password: { type: DataTypes.STRING, allowNull: false, comment:'用户密码' }, 8 | active: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true, comment:'是否正常状态' } 9 | }, 10 | { 11 | timestamps: true, 12 | underscored: true, 13 | // paranoid: true, 14 | freezeTableName: true, 15 | tableName: 'user', 16 | charset: 'utf8', 17 | collate: 'utf8_general_ci' 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /model/userAddress.js: -------------------------------------------------------------------------------- 1 | module.exports = function (sequelize, DataTypes) { 2 | return sequelize.define('UserAddress', { 3 | id: { type: DataTypes.BIGINT(11), autoIncrement: true, primaryKey: true, unique: true, comment:'主键' }, 4 | userId: { type: DataTypes.BIGINT(11), field: 'user_id', allowNull: false, comment:'用户Id' }, 5 | consignee : { type: DataTypes.STRING, field: 'consignee', allowNull: false, comment:'收货人' }, 6 | address: { type: DataTypes.STRING(1024), field: 'address', allowNull: false, comment:'详细地址' }, 7 | zipCode: { type: DataTypes.STRING(16), field: 'zip_code', allowNull: true, comment:'邮编' }, 8 | tel: { type: DataTypes.STRING(32), field: 'tel', allowNull: false, comment:'电话' }, 9 | }, 10 | { 11 | underscore: true, 12 | timestamps: false, 13 | freezeTableName: true, 14 | tableName: 'userAddress', 15 | comment: '用户地址表', 16 | charset: 'utf8', 17 | collate: 'utf8_general_ci', 18 | indexes: [{ 19 | name: 'userAddress_userId', 20 | method: 'BTREE', 21 | fields: ['user_id'] 22 | }] 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /model/userCheckin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (sequelize, DataTypes) { 4 | return sequelize.define('UserCheckin', { 5 | id: { type: DataTypes.BIGINT(11), autoIncrement: true, primaryKey: true, unique: true }, 6 | userId: { 7 | type: DataTypes.BIGINT(11), 8 | field: 'user_id', 9 | unique: true, 10 | references: { 11 | model: 'User', 12 | key: 'id' 13 | }, 14 | comment:'用户Id' }, 15 | loginIp: { type: DataTypes.STRING, field: 'login_ip', allowNull: false, defaultValue: '' , validate: {isIP: true}, comment:'登录IP'} 16 | }, 17 | { 18 | underscored: true, 19 | timestamps: true, 20 | tableName: 'userCheckin', 21 | comment: '用户登录信息', 22 | charset: 'utf8', 23 | collate: 'utf8_general_ci', 24 | indexes: [{ 25 | name: 'userCheckin_userId', 26 | method: 'BTREE', 27 | fields: ['user_id'] 28 | }] 29 | }); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sequelize_model_relation", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "body-parser": "~1.13.2", 10 | "cookie-parser": "~1.3.5", 11 | "debug": "~2.2.0", 12 | "ejs": "~2.3.3", 13 | "express": "~4.13.1", 14 | "morgan": "~1.6.1", 15 | "mysql": "^2.11.1", 16 | "sequelize": "^3.23.4", 17 | "serve-favicon": "~2.3.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /public/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | // 引用模型 4 | var User = require('../model').User; 5 | var UserCheckin = require('../model').UserCheckin; 6 | var UserAddress = require('../model').UserAddress; 7 | var Role = require('../model').Role; 8 | 9 | /* User和Role中插入数据 */ 10 | router.get('/', function(req, res, next) { 11 | Promise.all([ 12 | User.create({username:'itbilu', password:'itbilu.com'}), 13 | Role.create({roleName:'管理员'}) 14 | ]).then(function(results){ 15 | console.og(results[0]); 16 | res.set('Content-Type', 'text/html; charset=utf-8'); 17 | res.end('创建成功:'+JSON.stringify({user:results[0].dataValues, role:results[1].dataValues})); 18 | }).catch(next); 19 | }); 20 | 21 | // 向 UserCheckin 插入数据 22 | router.get('/create/checkin', function(res, res, next){ 23 | User.create({username:'itbilu', password:'itbilu.com'}).then(function(user){ 24 | 25 | var userCheckin = UserCheckin.build({loginIp:'127.0.0.1'}); 26 | user.setUserCheckin(userCheckin); 27 | 28 | res.set('Content-Type', 'text/html; charset=utf-8'); 29 | res.end('UserCheckin 插入数据成功'); 30 | }).catch(next); 31 | }); 32 | 33 | // N:M 插入数据 34 | router.get('/create/userRoles', function(res, res, next){ 35 | Promise.all([ 36 | User.create({username:'itbilu', password:'itbilu.com'}), 37 | Role.create({roleName:'管理员'}) 38 | ]).then(function(results){ 39 | var user = results[0]; 40 | var role = results[1]; 41 | user.setUserRoles(role); 42 | // 或 43 | // role.setUserRoles(user); 44 | res.set('Content-Type', 'text/html; charset=utf-8'); 45 | res.end('userRoles 插入数据成功'); 46 | }).catch(next); 47 | }); 48 | 49 | // 查询User及UserCheckin 50 | router.get('/select/user', function(res, res, next){ 51 | User.findOne({include:[UserCheckin]}).then(function(user){ 52 | console.log(user); 53 | res.set('Content-Type', 'text/html; charset=utf-8'); 54 | res.end(JSON.stringify(user)); 55 | }).catch(next); 56 | }); 57 | 58 | // 查询User及UserAdress 59 | router.get('/select/userAddress', function(res, res, next){ 60 | User.findOne().then(function(user){ 61 | user.getAddress(); 62 | res.set('Content-Type', 'text/html; charset=utf-8'); 63 | res.end(JSON.stringify(user)); 64 | }).catch(next); 65 | }); 66 | 67 | // 查询User及UserRoles 68 | router.get('/select/userRoles', function(res, res, next){ 69 | User.findOne().then(function(user){ 70 | user.getUserRoles(); 71 | res.set('Content-Type', 'text/html; charset=utf-8'); 72 | res.end(JSON.stringify(user)); 73 | }).catch(next); 74 | }); 75 | 76 | // 更新 userCheckin 77 | router.get('/update/userCheckin', function(res, res, next){ 78 | User.findOne({include:[UserCheckin]}).then(function(user){ 79 | var userCheckin = UserCheckin.build({userId:user.id, loginIp:'192.168.0.1'}); 80 | user.setUserCheckin(userCheckin); 81 | res.set('Content-Type', 'text/html; charset=utf-8'); 82 | res.end(JSON.stringify(user)); 83 | }).catch(next); 84 | }); 85 | 86 | // 删除 user 87 | router.get('/delete/user', function(res, res, next){ 88 | User.destroy({where:{id:2}}).then(function(result){ 89 | res.set('Content-Type', 'text/html; charset=utf-8'); 90 | res.end('删除完成'); 91 | }).catch(next); 92 | // 使用模型实例删除 93 | // User.findOne().then(function(user){ 94 | // user.destroy(); 95 | // res.set('Content-Type', 'text/html; charset=utf-8'); 96 | // res.end('删除完成'); 97 | // }).catch(next); 98 | }); 99 | 100 | // 删除 userCheckin 101 | router.get('/delete/userCheckin', function(res, res, next){ 102 | User.findOne({include:[UserCheckin]}).then(function(user){ 103 | user.setUserCheckin(null); 104 | res.set('Content-Type', 'text/html; charset=utf-8'); 105 | res.end(JSON.stringify(user)); 106 | }).catch(next); 107 | }); 108 | 109 | module.exports = router; 110 | -------------------------------------------------------------------------------- /views/error.ejs: -------------------------------------------------------------------------------- 1 |
<%= error.stack %>4 | -------------------------------------------------------------------------------- /views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
Welcome to <%= title %>
10 | 11 | 12 | --------------------------------------------------------------------------------