2016-09-21 219 views
0

我有一个遗留的数据库,它是盲目创建自动递增的ID,即使表中有一个完全有效的自然键。从本质上讲如何告诉SQLAlchemy为Session.merge(而不是PK)使用不同的身份规则?

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

目前没有好的办法来以合理的方式修改数据库,因为太多的遗留应用程序依赖于结构。

为了一个有形的例子,假设我们在表中有网络设备,并将其主机名作为自然键。该当前 DB会是这个样子:

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执行“插入或更新”。但是对于当前的模型,这实际上会导致错误(由于唯一的主机名限制)。

I 可能指定hostname列作为SA模型中的主键(并将PK原样保留在数据库中)。但是这看起来有点冒失。有没有一种更明确和可以理解的方式告诉SQLAlchemy它应该使用“主机名”作为标识?如果是,如何?

回答

0

在这种情况下,我发现最好谎言 sqlalchemy。告诉它,自然的关键是主要的。

class Device(Base): 
    hostname = Column(String(256), primary_key=True) 
    some_other_column = Column(String(20)) 
相关问题