当前位置: 首页 > news >正文

数据库编程-ORM

ORM(对象关系映射) 是一种编程技术,用于将数据库中的数据转换为面向对象的编程语言中的对象。

它简化了数据库操作,使开发者可以使用面向对象的方式来操作数据库,而不需要直接编写SQL语句。

Sequelize是一个基于Promise的Node.js ORM框架,支持多个SQL数据库(如MySQL、PostgreSQL、SQLite、MSSQL)。

Sequelize提供了一个易于使用的API来进行数据库建模、查询和事务处理。

Sequelize基础

Sequelize可以针对现有数据库或无数据库的情况进行创建。

const { Sequelize } = require("sequelize"); //command JS模块化//使用mysql ,一个数据库就对应一个Sequelize
const db = new Sequelize("mytestdb", "root", "******", {host: "localhost",dialect: "mysql", //数据库类型//   logging: false,//禁止打印sql语句(Sequelize语句)
});// 测试数据库连接
//authenticate()方法测试数据库连接;authenticate()返回promise
db.authenticate().then(() => {console.log("数据库连接成功");}).catch((err) => {console.log("数据库连接失败", err);});
//   Executing (default): SELECT 1+1 AS result// 输出Sequelize语句
// 数据库连接成功module.exports = db; //command JS导出

模型基础

模型是 Sequelize 的本质。模型是代表数据库中表的抽象。在Sequelize中,它是一个 Model 的扩展类。

模型应具有名称,但不必与它在数据库中表示的表的名称相同。

用法

调用sequelize.define(modelName, attributes, options)

import db from "./01-connect-db-ESM.js";
import { DataTypes } from "sequelize"; // 引入数据类型
// 定义模型 名称映射
// 名称写单数,数据库为负数。确保符合英语的复数规则。
const BookInfo = db.define("bookinfo",{id: {type: DataTypes.INTEGER,primaryKey: true,autoIncrement: true,},isbn: {type: DataTypes.CHAR(13),allowNull: false, //不能为空},name: {type: DataTypes.STRING(200),allowNull: false,},author: {type: DataTypes.STRING(100),allowNull: false,},press: {type: DataTypes.STRING(100),allowNull: false,},price: {type: DataTypes.DECIMAL(7, 2), // 7位长度,2位小数allowNull: false,},pubdate: {type: DataTypes.DATEONLY,allowNull: false,},},{// Sequelize默认会为每个模型添加createdAt和updatedAt字段,如果不需要则可以配置timestamps为false。timestamps: false, //时间戳//默认模型名称为复数。// tableName: "bookinfo", // 指定表名,不会按照模型名称自动生成复数。}
);export { BookInfo };

扩展Model并调用init(attributes, options)

class BookInfo extends Sequelize.Model {}BookInfo.init({id: {type: DataTypes.INTEGER,primaryKey: true,autoIncrement: true,},isbn: {type: DataTypes.CHAR(13),allowNull: false,},// ...pubdate: {type: DataTypes.DATEONLY,},},{sequelize,modelName: "bookinfos",timestamps: false,}
);

使用模型

建立模型后,即可通过模型对象所提供的API对数据进行增删查改(CRUD)操作

唯一查询

const book = await BookInfo.findOne({where: {isbn: "9787115383440",},
});
console.log(book.dataValues);
console.log(JSON.stringify(book, null, 2));

插入记录

const book = await BookInfo.create({isbn: "9787115383440",name: "JavaScript高级程序设计",author: "Nicholas C. Zakas",press: "机械工业出版社",price: 100,pubdate: "2018-01-01",
});
console.log(book.toJSON());

修改记录

const [affectedRows] = await BookInfo.update({price: 99.99,},{where: {isbn: "9787505051080",},}
);
console.log(affectedRows);

删除记录

// 删除一条记录
const count = await BookInfo.destroy({where: {isbn: "9787115383440",},
});
console.log(count);

模型优先

先构建模型,然后通过Sequelize创建数据库表。但,需要先在MySQL中创建对应的数据库。

创建Sequelize对象与“数据库优先”相同。

构建模型时,可以使用sequelize.define()方法,也可以使用扩展Model类的方式。

同步模型,使用sequelize.sync()方法,将模型同步到数据库。

Sequelize进阶

Sequelize 支持标准关联关系: 一对一、 一对多和多对多。

Sequelize 提供了四种关联类型

  • HasOne
  • BelongsTo
  • HasMany
  • BelongsToMany

HasOne

A.hasOne(B) 关联意味着 A 和 B 之间存在一对一的关系,外键在目标模型(B)中定义。

BelongsTo

A.belongsTo(B)关联意味着 A 和 B 之间存在一对一的关系,外键在源模型中定义(A)。

HasMany

A.hasMany(B) 关联意味着 A 和 B 之间存在一对多关系,外键在目标模型(B)中定义。

BelongsToMany

A.belongsToMany(B, { through: ‘C’ }) 关联意味着将表 C 用作联结表,在 A 和 B 之间存在多对多关系,具有外键(例如:aId 和 bId)。

关系映射

Sequelize 关联通常成对定义

  • 创建 一对一 关系,hasOne 和 belongsTo 关联一起使用。
  • 创建 一对多 关系,hasMany he belongsTo 关联一起使用。
  • 创建 多对多 关系,两个 belongsToMany 调用一起使用。

一对一关系

User与UserDetails为一对一的关系

import db from "../db/connect-db.js";
import { DataTypes, Model } from "sequelize";class User extends Model {}
User.init({id: {type: DataTypes.INTEGER,primaryKey: true,autoIncrement: true,allowNull: false,},username: {type: DataTypes.STRING(60),allowNull: false,validate: {len: [1, 60],is: /^[\w]+$/,//是否唯一:用一个回调函数,返回true或falseisUnique: async (value) => {const user = await User.findOne({where: { username: value },});if (user) {throw new Error("用户名已存在");}},},},password: {type: DataTypes.STRING(60),allowNull: false,validate: {len: [1, 60],},},// birthday: {//   type: DataTypes.DATEONLY,// },},{sequelize: db,modelName: "user", //小写的单数单词timestamps: false, //不生成时间戳}
);class UserDetail extends Model {}
UserDetail.init({id: {type: DataTypes.INTEGER,primaryKey: true,autoIncrement: true,},birthday: {type: DataTypes.DATEONLY,},address: {type: DataTypes.STRING(200),},phone: {type: DataTypes.CHAR(11),},},{sequelize: db,modelName: "userDetail",timestamps: false,tableName: "user_details",}
);//配置关系
User.hasOne(UserDetail, {foreignKey: "userId",as: "details",onDelete: "CASCADE", //级联删除
});
//可有可无
UserDetail.belongsTo(User, {foreignKey: "userId",
});export { User, UserDetail };

一对多关系

Category与BookInfo为一对多的关系。

import { Model, DataTypes } from "sequelize";
import { BookInfo } from "./bookinfo.js";
import db from "../db/connect-db.js";class Category extends Model {}
Category.init({id: {type: DataTypes.INTEGER,primaryKey: true,autoIncrement: true,},title: {type: DataTypes.STRING(100),allowNull: false,},},{sequelize: db,modelName: "category",timestamps: false,}
);Category.hasMany(BookInfo, {foreignKey: "cateId",as: "books",
});
BookInfo.belongsTo(Category, {foreignKey: "cateId",
});export { Category };

多对多关系

用户与书籍之间存在借阅关系,该关系为多对多。

// 定义借阅模型,用于跟踪图书的借阅情况。
const Borrowing = sequelize.define("borrowing",{id: {type: DataTypes.INTEGER,primaryKey: true,autoIncrement: true,},borrowDate: {type: DataTypes.DATE,defaultValue: DataTypes.NOW,},returnDate: {type: DataTypes.DATE,},},{timestamps: false,}
);
// 配置用户与书籍之间的借阅模型,该关系为多对多。
User.belongsToMany(BookInfo, {through: { model: Borrowing, unique: false },foreignKey: "userId",as: "borrowedBooks",otherKey: "bookId",
});BookInfo.belongsToMany(User, {through: { model: Borrowing, unique: false },foreignKey: "bookId",as: "borrowers",otherKey: "userId",
});

原始查询

使用 sequelize.query 方法,可以直接执行SQL语句。

const sql = `SELECT book.name, book.price, cate.title
FROM bookinfos as book, categories as cate
WHERE book.cateId = cate.id AND cate.id = ?`;const books = await sequelize.query(sql, {replacements: [1], // 参数替换type: sequelize.QueryTypes.SELECT, // 查询类型
});books.forEach((book) => {console.log(book.name, book.price, book.title);
});

关联参数

onDelete,用于配置删除时的数据库行为。

  • CASCADE:当父表中的记录被删除时,子表中与之关联的记录也会被删除。(多对多默认值)
  • SET NULL:当父表中的记录被删除时,子表中与之关联的外键列会被设置为NULL。(一对多、一对一的默认值)
  • RESTRICT:阻止删除父表中有关联的记录,除非先删除子表中的关联记录。
  • NO ACTION:与RESTRICT类似,阻止删除父表中有关联的记录。

onUpdate,用于配置修改时的数据库行为。

  • CASCADE:当父表中的主键值被更新时,子表中与之关联的外键值也会被更新。(一对多、一对一、多对多的默认值)
  • SET NULL:当父表中的主键值被更新时,子表中与之关联的外键值会被设置为NULL
  • RESTRICT:阻止更新父表中的主键值,除非先更新子表中的关联外键值。
  • NO ACTION:与RESTRICT类似,阻止更新父表中的主键值。
http://www.lqws.cn/news/598771.html

相关文章:

  • 基于Pandas和FineBI的昆明职位数据分析与可视化实现(四)- 职位数据可视化(FineBI)
  • Java-String类静态成员方法深度解析
  • HDMI 2.1 FRL协议的流控机制:切片传输(Slicing)和GAP插入
  • 开关电源和线性电源Multisim电路仿真实验汇总——硬件工程师笔记
  • 【SQL知识】PDO 和 MySQLi 的区别
  • Golang的并发编程实践总结
  • github代码中遇到的问题-解决方案
  • RNN和LSTM
  • flv.js视频/直播流测试demo
  • npm link的使用方法详细介绍
  • 动手实践:如何提取Python代码中的字符串变量的值
  • QML通过XMLHttpRequest实现HTTP通信
  • RocketMQ的广播消息和集群消息有什么区别?
  • 密码学(斯坦福)
  • 突破性进展:超短等离子体脉冲实现单电子量子干涉,为飞行量子比特奠定基础
  • 分布式爬虫数据存储开发实战
  • Hadoop、Spark、Flink 三大大数据处理框架的能力与应用场景
  • (LeetCode 面试经典 150 题) 42. 接雨水 (单调栈)
  • 数据分析与做菜的关系,makedown
  • 630,百度文心大模型4.5系列开源!真香
  • 牛客笔试AI智能监考:革新远程招聘,打造公平高效的笔试新时代
  • 力扣网C语言编程题:寻找两个正序数组的中位数
  • (LeetCode 每日一题) 3330. 找到初始输入字符串 I (字符串)
  • 8.4 Jmter实践不同线程组之间的全局变量的传递和使用
  • opencv入门(5)图像像素的读写操作和算术运算
  • VCenter SSL过期,登录提示HTTP 500错误解决办法
  • 应急响应靶机-linux1-知攻善防实验室
  • 动态库与符号表综合指南
  • Github CLI 快速 clone下载到本地教程
  • C# WPF + Helix Toolkit 实战:用两种方式打造“六面异色立方体”