首页 > 解决方案 > 如何检查小马 orm 缓存中是否存在对象?

问题描述

我正在尝试一些数据处理,然后一次性插入,表有一些复合键,我用它们来检查该 Id 的记录是否存在,然后它应该更新记录而不是创建。

虽然数据处理有可能在样本数据中多次存在相同的 ID,并且在处理时它不会在 db 中找到与该 ID 匹配的记录,因此它每次都尝试创建记录。

有什么方法可以检查缓存中的复合键匹配吗?

标签: python-3.6ponyorm

解决方案


您可以使用get实体实例的方法通过主键值的组合来查找对象。

get方法搜索db_session缓存和数据库,None如果没有找到对象则返回:

from pony import orm

db = orm.Database('sqlite', ':memory:')

class Point(db.Entity):
    x = orm.Required(int)
    y = orm.Required(int)
    description = orm.Optional(str)
    orm.PrimaryKey(x, y)

db.generate_mapping(create_tables=True)

points = [(1, 2, 'foo'), (3, 4, 'bar'), (1, 2, 'baz'), (5, 6, 'qux')]

with orm.db_session:
    for a, b, s in points:
        point = Point.get(x=a, y=b)
        if point is None:
            point = Point(x=a, y=b, description=s)

get方法也适用于辅助复合键

您还可以使用方括号搜索实体实例并捕获异常:

with orm.db_session:
    try:
        point = Point[10, 20]
    except orm.ObjectNotFound:
        point = Point(x=10, y=20)

更新:关于 IdentityMap 模式使用的说明

PonyORM 使用 IdentityMap 设计模式。这意味着在 adb_session中加载或创建的同一类的所有对象都由其主键值索引。同一类的多个对象不可能在同一个db_session. 如果get使用相同的主键值多次调用该方法,它将返回相同的实例:

with db_session:
    a = Point.get(x=10, y=20)
    b = Point.get(x=10, y=20)
    assert a is b  # the same object!

这同样适用于您刚刚创建一个对象然后尝试get使用相同主键创建对象的情况:Pony 将返回您刚刚创建的对象:

with db_session:
    a = Point.get(x=10, y=20)
    if a is None:
        a = Point(x=10, y=20)

    # later, in the same db_session:
    b = Point.get(x=10, y=20)
    assert a is b  # the same object, not saved yet

另一方面,如果您尝试使用相同的主键创建两个不同的对象,您将收到错误消息:

with db_session:
    a = Point(x=10, y=20)
    b = Point(x=10, y=20)

Traceback (most recent call last):
    ...
pony.orm.core.CacheIndexError: Cannot create Point: instance with primary key 10, 20 already exists

另外,如果你试图创建一个已经存在于数据库中的对象而不检查它,你会得到一个错误:

with db_session:
    a = Point(x=30, y=40)

with db_session:
    b = Point(x=30, y=40)

Traceback (most recent call last):
    ...
pony.orm.core.TransactionIntegrityError: Object Point[30, 40] cannot be stored in the database. IntegrityError: UNIQUE constraint failed: Point.x, Point.y

为了避免此错误,您可以get在创建新对象之前检查对象是否存在。


推荐阅读