我有一个遗留数据库,它是用自动增量ID盲目创建的,即使表中有一个完全有效的自然键。
最终会出现代码乱码的代码:
Fetch row with natural key 'x'
if exists:
update row with NK 'x'
else:
insert row with NK 'x'
基本上是一个upsert。
这个用例(upsert)由SQLAlchemy的Session.merge()涵盖。但SA只会查看表的主键以协调它是否必须进行插入或更新。然而,在现有的数据库中,PK确实 - 与应该所做的相反 - 不代表行的真实身份。因此,相同的标识可以与多个自动增量ID一起出现。还有一些其他业务规则可以确保唯一性。但是今天的ID 1
明天可以是ID 3246
!
目前还没有很好的方法以合理的方式修改数据库,因为太多的遗留应用程序依赖于结构。
为了一个有形的例子,假设我们在表中有网络设备,并将其主机名作为自然键。 当前数据库看起来像这样:
CREATE TABLE device (
id SERIAL PRIMARY KEY,
hostname TEXT UNIQUE,
some_other_column TEXT
)
相应的SA模型:
class Device(Base):
id = Column(Integer, primary_key=True)
hostname = Column(String(256))
some_other_column = Column(String(20))
我希望能够做到以下几点:
mydevice = Device(hostname='hello-world', some_other_column='foo')
merged_device = session.merge(mydevice)
session.commit()
在这个例子中,我希望SA进行“插入或更新”。但是使用当前模型,这实际上会导致错误(由于唯一的主机名约束)。
我可以将hostname
列指定为SA模型中的主键(并将PK保留在DB中)。但这看起来有点黑客。是否有更明确和可理解的方式告诉SQLAlchemy它应该使用“hostname”作为身份?如果是的话,怎么样?
答案 0 :(得分:1)
在这样的情况下,我发现最好谎言到sqlalchemy。告诉它自然键是主键。
class Device(Base):
hostname = Column(String(256), primary_key=True)
some_other_column = Column(String(20))