SqlAlchemy 2.0 中文文档(十七)(2)

简介: SqlAlchemy 2.0 中文文档(十七)

SqlAlchemy 2.0 中文文档(十七)(1)https://developer.aliyun.com/article/1562952


禁用对具有多个参数集的 UPDATE 语句进行按主键的 ORM 批量更新

当:

  1. 给出的 UPDATE 语句针对 ORM 实体
  2. Session 用于执行语句,而不是核心 Connection
  3. 传递的参数是字典列表

为了调用不使用“按主键的 ORM 批量更新”的 UPDATE 语句,直接使用 Session.connection() 方法对当前事务获取 Connection 执行语句:

>>> from sqlalchemy import bindparam
>>> session.connection().execute(
...     update(User).where(User.name == bindparam("u_name")),
...     [
...         {"u_name": "spongebob", "fullname": "Spongebob Squarepants"},
...         {"u_name": "patrick", "fullname": "Patrick Star"},
...     ],
... )
UPDATE  user_account  SET  fullname=?  WHERE  user_account.name  =  ?
[...]  [('Spongebob Squarepants',  'spongebob'),  ('Patrick Star',  'patrick')]
<...>

另请参阅

按主键每行的 ORM 批量更新要求记录包含主键值 ### 联合表继承的按主键批量更新

当使用具有联合表继承的映射时,ORM 批量更新的行为与使用映射进行批量插入时类似;如 联合表继承的批量插入 中所述,批量更新操作将为映射中表示的每个表发出一条 UPDATE 语句,其中给定的参数包括要更新的值(不受影响的表将被跳过)。

示例:

>>> session.execute(
...     update(Manager),
...     [
...         {
...             "id": 1,
...             "name": "scheeks",
...             "manager_name": "Sandy Cheeks, President",
...         },
...         {
...             "id": 2,
...             "name": "eugene",
...             "manager_name": "Eugene H. Krabs, VP Marketing",
...         },
...     ],
... )
UPDATE  employee  SET  name=?  WHERE  employee.id  =  ?
[...]  [('scheeks',  1),  ('eugene',  2)]
UPDATE  manager  SET  manager_name=?  WHERE  manager.id  =  ?
[...]  [('Sandy Cheeks, President',  1),  ('Eugene H. Krabs, VP Marketing',  2)]
<...>
```### 旧版会话批量更新方法
如传统会话批量 INSERT 方法所讨论的,`Session.bulk_update_mappings()`方法是批量更新的传统形式,当解释具有给定主键参数的`update()`语句时,ORM 在内部使用它;但是,当使用传统版本时,诸如会话同步支持之类的功能是不包括的。
下面的示例:
```py
session.bulk_update_mappings(
 User,
 [
 {"id": 1, "name": "scheeks", "manager_name": "Sandy Cheeks, President"},
 {"id": 2, "name": "eugene", "manager_name": "Eugene H. Krabs, VP Marketing"},
 ],
)

使用新 API 表示为:

from sqlalchemy import update
session.execute(
 update(User),
 [
 {"id": 1, "name": "scheeks", "manager_name": "Sandy Cheeks, President"},
 {"id": 2, "name": "eugene", "manager_name": "Eugene H. Krabs, VP Marketing"},
 ],
)

请参见

传统会话批量 INSERT 方法 ## 使用自定义 WHERE 条件的 ORM UPDATE 和 DELETE

当使用自定义 WHERE 条件构造UpdateDelete构造时(即使用Update.where()Delete.where()方法),可以通过将它们传递给Session.execute()在 ORM 上下文中调用,而不使用Session.execute.params参数。对于Update,要更新的值应该使用Update.values()传递。

此使用模式与之前描述的功能不同 ORM 按主键批量更新,ORM 使用给定的 WHERE 子句,而不是将 WHERE 子句固定为主键。这意味着单个 UPDATE 或 DELETE 语句可以一次性影响许多行。

举例来说,下面发出一个 UPDATE,影响多行的“fullname”字段

>>> from sqlalchemy import update
>>> stmt = (
...     update(User)
...     .where(User.name.in_(["squidward", "sandy"]))
...     .values(fullname="Name starts with S")
... )
>>> session.execute(stmt)
UPDATE  user_account  SET  fullname=?  WHERE  user_account.name  IN  (?,  ?)
[...]  ('Name starts with S',  'squidward',  'sandy')
<...>

对于 DELETE,基于条件删除行的示例:

>>> from sqlalchemy import delete
>>> stmt = delete(User).where(User.name.in_(["squidward", "sandy"]))
>>> session.execute(stmt)
DELETE  FROM  user_account  WHERE  user_account.name  IN  (?,  ?)
[...]  ('squidward',  'sandy')
<...>

警告

请阅读以下部分 ORM 启用更新和删除的重要注意事项和注意事项,以了解 ORM 启用的 UPDATE 和 DELETE 功能与 ORM 工作单元 功能的功能不同,例如使用Session.delete()方法删除单个对象。

ORM-启用的 Update 和 Delete 的重要说明和注意事项

ORM 启用的 UPDATE 和 DELETE 功能绕过 ORM 工作单元 自动化,以便能够发出一条匹配多行的 UPDATE 或 DELETE 语句,而不会复杂化。

  • 操作不提供 Python 中的关系级联功能 - 假定任何需要的外键引用都已配置为 ON UPDATE CASCADE  和/或 ON DELETE CASCADE,否则如果强制执行外键引用,则数据库可能会发出完整性违规。有关一些示例,请参阅使用外键 ON  DELETE cascade 与 ORM 关系的注意事项。
  • 在 UPDATE 或 DELETE 之后,Session 中受到影响的依赖对象,特别是那些引用现在已被删除的行的 ON UPDATE CASCADE 或 ON DELETE CASCADE 的相关表的对象,可能仍然引用这些对象。此问题在 Session 过期时解决,通常发生在 Session.commit() 时或可以通过使用 Session.expire_all() 强制执行。
  • 启用 ORM 的 UPDATE 和 DELETE 不会自动处理连接的表继承。有关如何处理连接继承映射的说明,请参阅具有自定义 WHERE 条件的连接表继承的 UPDATE/DELETE 部分。
  • 为了将单表继承映射的多态标识限制为特定子类所需的 WHERE 条件会自动包含。这仅适用于没有自己表的子类映射器。
  • ORM 更新和删除操作支持 with_loader_criteria() 选项;此处的条件将被添加到正在发出的 UPDATE 或 DELETE 语句的条件中,并在“同步”过程中考虑。
  • 要拦截启用 ORM 的 UPDATE 和 DELETE 操作以使用事件处理程序,请使用SessionEvents.do_orm_execute()事件。 ### 选择同步策略

在使用update()delete()与启用 ORM 执行一起使用Session.execute()时,将存在额外的 ORM 特定功能,该功能将同步语句更改的状态与当前存在于Session的 identity map 中的对象的状态。通过“同步”,我们指的是更新的属性将使用新值刷新,或者至少过期,以便在下次访问时重新填充其新值,并且删除的对象将移至 deleted 状态。

此同步可通过“同步策略”控制,该策略作为字符串 ORM 执行选项传递,通常使用Session.execute.execution_options 字典:

>>> from sqlalchemy import update
>>> stmt = (
...     update(User).where(User.name == "squidward").values(fullname="Squidward Tentacles")
... )
>>> session.execute(stmt, execution_options={"synchronize_session": False})
UPDATE  user_account  SET  fullname=?  WHERE  user_account.name  =  ?
[...]  ('Squidward Tentacles',  'squidward')
<...>

执行选项也可以与语句本身捆绑在一起,使用Executable.execution_options() 方法:

>>> from sqlalchemy import update
>>> stmt = (
...     update(User)
...     .where(User.name == "squidward")
...     .values(fullname="Squidward Tentacles")
...     .execution_options(synchronize_session=False)
... )
>>> session.execute(stmt)
UPDATE  user_account  SET  fullname=?  WHERE  user_account.name  =  ?
[...]  ('Squidward Tentacles',  'squidward')
<...>

支持以下synchronize_session的值:

  • 'auto' - 这是默认值。在支持 RETURNING 的后端上将使用 'fetch' 策略,这包括除 MySQL 外的所有 SQLAlchemy 本机驱动程序。如果不支持 RETURNING,则将改为使用 'evaluate' 策略。
  • 'fetch' - 通过在执行 UPDATE 或 DELETE 之前执行 SELECT 或使用 RETURNING(如果数据库支持)来检索受影响行的主键标识,以便受操作影响的内存对象可以使用新值刷新(更新)或从Session中删除(删除)。即使给定的update()delete()构造明确指定实体或列使用UpdateBase.returning(),也可以使用此同步策略。
    2.0 版中的更改:在使用启用 ORM 的 UPDATE 和 DELETE 以 WHERE 条件时,可以将明确的UpdateBase.returning()'fetch' 同步策略结合使用。实际语句将包含'fetch'策略所需的列和请求的列之间的并集。
  • 'evaluate' - 这表示在 Python 中评估 UPDATE 或 DELETE 语句中给定的 WHERE 条件,以定位Session中的匹配对象。这种方法不会为操作添加任何 SQL 往返,并且在没有 RETURNING 支持的情况下,可能更有效。对于具有复杂条件的 UPDATE 或 DELETE 语句,'evaluate' 策略可能无法在 Python 中评估表达式,并且会引发错误。如果发生这种情况,请改用该操作的 'fetch' 策略。
    提示
    如果 SQL 表达式使用Operators.op()custom_op 功能使用自定义运算符,则可以使用 Operators.op.python_impl 参数指示将由"evaluate"同步策略使用的 Python 函数。
    2.0 版中的新功能。
    警告
    如果要在具有许多已过期对象的Session上运行 UPDATE 操作,则应避免使用"evaluate"策略,因为它将必须刷新对象以便根据给定的 WHERE 条件测试它们,这将为每个对象发出一个 SELECT。在这种情况下,特别是如果后端支持 RETURNING,则应优先选择"fetch"策略。
  • False - 不同步会话。该选项对于不支持 RETURNING 的后端可能很有用,其中无法使用"evaluate"策略。在这种情况下,Session 中对象的状态不变,不会自动对应于发出的 UPDATE 或 DELETE 语句,如果存在通常与匹配行对应的对象。### 使用 UPDATE/DELETE 和自定义 WHERE 条件的 RETURNING

UpdateBase.returning() 方法与启用 ORM 的 UPDATE 和 DELETE 以 WHERE 条件完全兼容。完整的 ORM 对象和/或列可以用于 RETURNING:

>>> from sqlalchemy import update
>>> stmt = (
...     update(User)
...     .where(User.name == "squidward")
...     .values(fullname="Squidward Tentacles")
...     .returning(User)
... )
>>> result = session.scalars(stmt)
UPDATE  user_account  SET  fullname=?  WHERE  user_account.name  =  ?
RETURNING  id,  name,  fullname,  species
[...]  ('Squidward Tentacles',  'squidward')
>>> print(result.all())
[User(name='squidward', fullname='Squidward Tentacles')]

RETURNING 的支持也与 fetch 同步策略兼容,fetch 同样使用 RETURNING。ORM 将适当地组织 RETURNING 中的列,以便同步进程顺利进行,并且返回的 Result 将以请求的实体和 SQL 列的请求顺序包含。

2.0 版中的新功能:UpdateBase.returning() 可用于启用 ORM 的 UPDATE 和 DELETE,并仍保留与 fetch 同步策略的完全兼容性。### 使用自定义 WHERE 条件进行连接表继承的 UPDATE/DELETE

带有 WHERE 条件的 UPDATE/DELETE 功能,不像 基于主键的 ORM 大规模 UPDATE,每次调用 Session.execute() 时只发出单个 UPDATE 或 DELETE 语句。这意味着当针对多表映射运行 update()delete() 语句时,如连接表继承映射中的子类,该语句必须符合后端当前的功能,这可能包括后端不支持引用多个表的 UPDATE 或 DELETE  语句,或者仅对此有限支持。这意味着对于诸如连接继承子类之类的映射,UPDATE/DELETE 功能的 ORM  版本只能在有限程度上使用或根本无法使用,具体取决于具体情况。

对于连接表子类发出多行 UPDATE 语句的最直接方法是仅引用子表。这意味着 Update() 构造应仅引用本地于子类表的属性,如下例所示:

>>> stmt = (
...     update(Manager)
...     .where(Manager.id == 1)
...     .values(manager_name="Sandy Cheeks, President")
... )
>>> session.execute(stmt)
UPDATE  manager  SET  manager_name=?  WHERE  manager.id  =  ?
[...]  ('Sandy Cheeks, President',  1)
<...> 

使用上述形式,一个简单的方法是引用基表来定位任何 SQL 后端上的行,可以使用子查询:

>>> stmt = (
...     update(Manager)
...     .where(
...         Manager.id
...         == select(Employee.id).where(Employee.name == "sandy").scalar_subquery()
...     )
...     .values(manager_name="Sandy Cheeks, President")
... )
>>> session.execute(stmt)
UPDATE  manager  SET  manager_name=?  WHERE  manager.id  =  (SELECT  employee.id
FROM  employee
WHERE  employee.name  =  ?)  RETURNING  id
[...]  ('Sandy Cheeks, President',  'sandy')
<...>

对于支持 UPDATE…FROM 的后端,子查询可以作为额外的普通 WHERE 条件陈述,但是两个表之间的条件必须以某种方式明确陈述:

>>> stmt = (
...     update(Manager)
...     .where(Manager.id == Employee.id, Employee.name == "sandy")
...     .values(manager_name="Sandy Cheeks, President")
... )
>>> session.execute(stmt)
UPDATE  manager  SET  manager_name=?  FROM  employee
WHERE  manager.id  =  employee.id  AND  employee.name  =  ?
[...]  ('Sandy Cheeks, President',  'sandy')
<...>

对于 DELETE 操作,预期基表和子表中的行将同时被 DELETE。要在不使用级联外键的情况下 DELETE 多行连接继承对象,应分别发出针对每个表的 DELETE:

>>> from sqlalchemy import delete
>>> session.execute(delete(Manager).where(Manager.id == 1))
DELETE  FROM  manager  WHERE  manager.id  =  ?
[...]  (1,)
<...>
>>> session.execute(delete(Employee).where(Employee.id == 1))
DELETE  FROM  employee  WHERE  employee.id  =  ?
[...]  (1,)
<...>

总的来说,对于更新和删除联合继承和其他多表映射的行,应优先使用普通的工作单元流程,除非存在使用自定义 WHERE 条件的性能原因。

旧版查询方法

原始的 ORM 启用的带有 WHERE 功能的 UPDATE/DELETE 最初是 Query 对象的一部分,位于 Query.update()Query.delete() 方法中。这些方法仍然可用,并提供与 ORM UPDATE and DELETE with Custom WHERE Criteria 描述的部分相同的功能。主要区别在于旧版方法不提供显式的 RETURNING 支持。

请参阅

Query.update()

Query.delete() ## ORM 批量插入语句

可以基于 ORM 类构建 insert() 构造,并将其传递给 Session.execute() 方法。发送到 Session.execute.params 参数的参数字典列表,与 Insert 对象本身分开,将为语句调用批量插入模式,这基本上意味着操作将尽可能地为许多行进行优化:

>>> from sqlalchemy import insert
>>> session.execute(
...     insert(User),
...     [
...         {"name": "spongebob", "fullname": "Spongebob Squarepants"},
...         {"name": "sandy", "fullname": "Sandy Cheeks"},
...         {"name": "patrick", "fullname": "Patrick Star"},
...         {"name": "squidward", "fullname": "Squidward Tentacles"},
...         {"name": "ehkrabs", "fullname": "Eugene H. Krabs"},
...     ],
... )
INSERT  INTO  user_account  (name,  fullname)  VALUES  (?,  ?)
[...]  [('spongebob',  'Spongebob Squarepants'),  ('sandy',  'Sandy Cheeks'),  ('patrick',  'Patrick Star'),
('squidward',  'Squidward Tentacles'),  ('ehkrabs',  'Eugene H. Krabs')]
<...>

参数字典包含键值对,这些键值对可能对应于与映射的 Columnmapped_column() 声明相对应的 ORM 映射属性,以及与组合声明相对应的映射。如果这两个名称恰好不同,则键应与ORM 映射属性名称匹配,而不是实际的数据库列名称。

2.0 版本中的更改:将 Insert 结构传递给 Session.execute() 方法现在会调用“批量插入”,这利用了与传统的 Session.bulk_insert_mappings() 方法相同的功能。这与 1.x 系列中的行为变化相比,1.x 系列中 Insert 将以核心为中心的方式解释,使用列名作为值键;现在接受 ORM 属性键。通过将执行选项 {"dml_strategy": "raw"} 传递给 Session.execute() 方法的 Session.execution_options 参数,可以使用核心样式功能。


SqlAlchemy 2.0 中文文档(十七)(3)https://developer.aliyun.com/article/1562954

相关文章
|
3月前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(十七)(3)
SqlAlchemy 2.0 中文文档(十七)
34 4
|
3月前
|
SQL 关系型数据库 API
SqlAlchemy 2.0 中文文档(十七)(4)
SqlAlchemy 2.0 中文文档(十七)
53 4
|
3月前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(十七)(1)
SqlAlchemy 2.0 中文文档(十七)
21 1
|
3月前
|
SQL 关系型数据库 MySQL
SqlAlchemy 2.0 中文文档(十七)(5)
SqlAlchemy 2.0 中文文档(十七)
25 1
|
3月前
|
SQL 缓存 数据库连接
SqlAlchemy 2.0 中文文档(二十二)(3)
SqlAlchemy 2.0 中文文档(二十二)
19 5
|
3月前
|
SQL 测试技术 知识图谱
SqlAlchemy 2.0 中文文档(十五)(4)
SqlAlchemy 2.0 中文文档(十五)
34 1
|
3月前
|
SQL Oracle 关系型数据库
SqlAlchemy 2.0 中文文档(十五)(1)
SqlAlchemy 2.0 中文文档(十五)
39 1
|
3月前
|
SQL Python
SqlAlchemy 2.0 中文文档(十五)(5)
SqlAlchemy 2.0 中文文档(十五)
67 1
|
3月前
|
SQL 测试技术 知识图谱
SqlAlchemy 2.0 中文文档(十五)(3)
SqlAlchemy 2.0 中文文档(十五)
28 1
|
3月前
|
SQL 测试技术 API
SqlAlchemy 2.0 中文文档(十五)(2)
SqlAlchemy 2.0 中文文档(十五)
73 1
下一篇
无影云桌面