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