2

我有一个关于 SQLAlchemy 中实体映射的问题。

我有一个瞬态对象,它已经包含一些持久对象的外键。我希望 SQLAlchemy 获取引用的对象并将它们分配给它们的关系属性。从 SQLAlchemy 文档中,我认为我必须在会话上使用合并操作来实现这一点。但在我的配置中,它不起作用。

这是展示我的问题的最小示例:

# -*- coding: utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy.orm import mapper
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
from sqlalchemy.orm import relationship, sessionmaker

class User(object):
    def __init__(self, id, name, fullname, password, best_friend_id=None):
        self.id = id
        self.name = name
        self.fullname = fullname
        self.password = password
        self.best_friend_id = best_friend_id

    def __repr__(self):
        return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password)


class Dog(object):
    def __init__(self, id, name):
        self.id = id
        self.name = name

    def __repr__(self):
        return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password)

engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
metadata = MetaData()

dogs_table = Table('dogs', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String),
)


users_table = Table('users', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String),
    Column('fullname', String),
    Column('password', String),
    Column('best_friend_id', Integer, ForeignKey('dogs.id'))
)

metadata.create_all(engine)
mapper(User, users_table, properties={'best_friend': relationship(Dog, uselist=False)})
mapper(Dog, dogs_table)

dog = Dog(id=1, name='Hasso')
lordling = User(id=2, name='John', fullname='Miller', password='very_secret', best_friend_id=1)

session.add(dog)
session.commit()

merged_lordling = session.merge(lordling)
print str(merged_lordling.best_friend.name)

我希望它merged_lordling.best_friend包含狗'Hasso'。但它仍然是None

4

1 回答 1

1

我最近被同样的问题所困扰。建立关系后,您应该直接将Dog实例分配给User.best_friend,而不是显式使用外键。我不知道为什么会发生这种情况,但是在调查一个类似的问题时,我意识到如果你这样做,SQLAlchemy 不会填充关系属性,直到你刷新所有相关实例。

所以,而不是:

dog = Dog(id=1, name='Hasso')
lordling = User(id=2, name='John', fullname='Miller', password='very_secret', 
                best_friend_id=1)

session.add(dog)

只需这样做:

dog = Dog(id=1, name='Hasso')
lordling = User(id=2, name='John', fullname='Miller', password='very_secret', 
                best_friend=dog)

session.add(lordling)

甚至:

lordling = User(id=2, name='John', fullname='Miller', password='very_secret', 
                best_friend=Dog(id=1, name='Hasso'))
session.add(lordling)    

作为一般规则,在建立关系时避免直接使用外键列。拥抱 ORM,只有当你真的别无选择时,才直接从外键分配或查询。我很难学到这一点。

于 2013-11-08T23:18:27.833 回答