SQLAlchemy ORM - การลบวัตถุที่เกี่ยวข้อง
ง่ายต่อการดำเนินการลบบนตารางเดียว สิ่งที่คุณต้องทำคือลบอ็อบเจ็กต์ของคลาสที่แมปออกจากเซสชันและคอมมิตการดำเนินการ อย่างไรก็ตามการดำเนินการลบบนตารางที่เกี่ยวข้องหลายตารางนั้นยุ่งยากเล็กน้อย
ในฐานข้อมูล sales.db ของเราคลาสลูกค้าและใบแจ้งหนี้จะถูกแมปกับลูกค้าและตารางใบแจ้งหนี้ที่มีความสัมพันธ์แบบหนึ่งต่อหลายประเภท เราจะพยายามลบวัตถุของลูกค้าและดูผลลัพธ์
เพื่อเป็นข้อมูลอ้างอิงอย่างรวดเร็วด้านล่างนี้คือคำจำกัดความของคลาสลูกค้าและใบแจ้งหนี้ -
from sqlalchemy import create_engine, ForeignKey, Column, Integer, String
engine = create_engine('sqlite:///sales.db', echo = True)
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
from sqlalchemy.orm import relationship
class Customer(Base):
__tablename__ = 'customers'
id = Column(Integer, primary_key = True)
name = Column(String)
address = Column(String)
email = Column(String)
class Invoice(Base):
__tablename__ = 'invoices'
id = Column(Integer, primary_key = True)
custid = Column(Integer, ForeignKey('customers.id'))
invno = Column(Integer)
amount = Column(Integer)
customer = relationship("Customer", back_populates = "invoices")
Customer.invoices = relationship("Invoice", order_by = Invoice.id, back_populates = "customer")
เราตั้งค่าเซสชันและรับวัตถุของลูกค้าโดยการค้นหาด้วยรหัสหลักโดยใช้โปรแกรมด้านล่าง -
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
x = session.query(Customer).get(2)
ในตารางตัวอย่างของเรา x.name เป็น 'Gopal Krishna' ให้เราลบ x นี้ออกจากเซสชันและนับการเกิดชื่อนี้
session.delete(x)
session.query(Customer).filter_by(name = 'Gopal Krishna').count()
นิพจน์ SQL ที่ได้จะส่งกลับ 0
SELECT count(*)
AS count_1
FROM (
SELECT customers.id
AS customers_id, customers.name
AS customers_name, customers.address
AS customers_address, customers.email
AS customers_email
FROM customers
WHERE customers.name = ?)
AS anon_1('Gopal Krishna',) 0
อย่างไรก็ตามออบเจ็กต์ใบแจ้งหนี้ที่เกี่ยวข้องของ x ยังคงอยู่ที่นั่น สามารถตรวจสอบได้ด้วยรหัสต่อไปนี้ -
session.query(Invoice).filter(Invoice.invno.in_([10,14])).count()
ในที่นี้ 10 และ 14 เป็นหมายเลขใบแจ้งหนี้ของลูกค้า Gopal Krishna ผลลัพธ์ของแบบสอบถามข้างต้นคือ 2 ซึ่งหมายความว่าวัตถุที่เกี่ยวข้องยังไม่ถูกลบ
SELECT count(*)
AS count_1
FROM (
SELECT invoices.id
AS invoices_id, invoices.custid
AS invoices_custid, invoices.invno
AS invoices_invno, invoices.amount
AS invoices_amount
FROM invoices
WHERE invoices.invno IN (?, ?))
AS anon_1(10, 14) 2
เนื่องจาก SQLAlchemy ไม่ถือว่าการลบ cascade; เราต้องให้คำสั่งเพื่อลบมัน
ในการเปลี่ยนลักษณะการทำงานเรากำหนดค่าตัวเลือกการเรียงซ้อนบนความสัมพันธ์ User.addresses ให้เราปิดเซสชันที่กำลังดำเนินอยู่ใช้ new declarative_base () และประกาศคลาสผู้ใช้อีกครั้งโดยเพิ่มความสัมพันธ์ที่อยู่รวมถึงการกำหนดค่าแบบเรียงซ้อน
แอ็ตทริบิวต์ cascade ในฟังก์ชันความสัมพันธ์คือรายการกฎการเรียงลำดับที่คั่นด้วยเครื่องหมายจุลภาคซึ่งกำหนดว่าการดำเนินการของเซสชันควร "เรียงซ้อน" จากระดับบนไปยังลูกอย่างไร โดยค่าเริ่มต้นจะเป็น False ซึ่งหมายความว่า "บันทึกอัปเดตผสาน"
น้ำตกที่มีอยู่มีดังนี้ -
- save-update
- merge
- expunge
- delete
- delete-orphan
- refresh-expire
ตัวเลือกที่มักใช้คือ "all, delete-orphan" เพื่อระบุว่าอ็อบเจ็กต์ที่เกี่ยวข้องควรตามมาพร้อมกับอ็อบเจ็กต์พาเรนต์ในทุกกรณีและจะถูกลบเมื่อยกเลิกการเชื่อมโยง
ดังนั้นคลาสลูกค้าที่ประกาศใหม่ดังแสดงด้านล่าง -
class Customer(Base):
__tablename__ = 'customers'
id = Column(Integer, primary_key = True)
name = Column(String)
address = Column(String)
email = Column(String)
invoices = relationship(
"Invoice",
order_by = Invoice.id,
back_populates = "customer",
cascade = "all,
delete, delete-orphan"
)
ให้เราลบลูกค้าที่มีชื่อ Gopal Krishna โดยใช้โปรแกรมด้านล่างและดูจำนวนวัตถุใบแจ้งหนี้ที่เกี่ยวข้อง -
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind = engine)
session = Session()
x = session.query(Customer).get(2)
session.delete(x)
session.query(Customer).filter_by(name = 'Gopal Krishna').count()
session.query(Invoice).filter(Invoice.invno.in_([10,14])).count()
ตอนนี้จำนวนเป็น 0 พร้อมด้วย SQL ต่อไปนี้ที่ปล่อยออกมาโดยสคริปต์ด้านบน -
SELECT customers.id
AS customers_id, customers.name
AS customers_name, customers.address
AS customers_address, customers.email
AS customers_email
FROM customers
WHERE customers.id = ?
(2,)
SELECT invoices.id
AS invoices_id, invoices.custid
AS invoices_custid, invoices.invno
AS invoices_invno, invoices.amount
AS invoices_amount
FROM invoices
WHERE ? = invoices.custid
ORDER BY invoices.id (2,)
DELETE FROM invoices
WHERE invoices.id = ? ((1,), (2,))
DELETE FROM customers
WHERE customers.id = ? (2,)
SELECT count(*)
AS count_1
FROM (
SELECT customers.id
AS customers_id, customers.name
AS customers_name, customers.address
AS customers_address, customers.email
AS customers_email
FROM customers
WHERE customers.name = ?)
AS anon_1('Gopal Krishna',)
SELECT count(*)
AS count_1
FROM (
SELECT invoices.id
AS invoices_id, invoices.custid
AS invoices_custid, invoices.invno
AS invoices_invno, invoices.amount
AS invoices_amount
FROM invoices
WHERE invoices.invno IN (?, ?))
AS anon_1(10, 14)
0