我有一个用关系定义的表,我注意到即使我在查询中没有使用 join ,仍然会检索信息:
class Employee(Base):
__tablename__ = "t_employee"
id = Column(Identifier(20), Sequence('%s_id_seq' % __tablename__), primary_key=True, nullable=False)
jobs = relationship("EmployeeJob")
roles = relationship("EmployeeRole")
class EmployeeJob(Base):
__tablename__ = "t_employee_job"
id = Column(Integer(20), Sequence('%s_id_seq' % __tablename__), primary_key=True, nullable=False)
employee_id = Column(Integer(20), ForeignKey('t_employee.id', ondelete="CASCADE"), primary_key=True)
job_id = Column(Integer(20), ForeignKey('t_job.id', ondelete="CASCADE"), primary_key=True)
class EmployeeRole(Base):
__tablename__ = "t_employee_role"
id = Column(Integer(20), Sequence('%s_id_seq' % __tablename__), primary_key=True, nullable=False)
employee_id = Column(Integer(20), ForeignKey('t_employee.id', ondelete="CASCADE"), nullable=False)
location_id = Column(Identifier(20), ForeignKey('t_location.id', ondelete="CASCADE"))
role_id = Column(Integer(20), ForeignKey('t_role.id', ondelete="CASCADE"), nullable=False)
session.query(Employee).all()
还检索角色和作业,但通过查询每行的数据库来执行此操作。
我对这种情况有2个问题:
1.在性能方面,我想我应该自己做加入。我是对的吗?
2.如何将表映射到某个数据结构?例如,我想获得具有其角色的员工列表,其中每个角色应由位置ID和角色ID的数组表示,例如, {id:1, jobs:[1,2,3], roles:[[1,1],[1,2],[2,3]]}
答案 0 :(得分:2)
1)请阅读SA文档中的Eager Loading。 默认情况下,关系在首次访问时会加载延迟。在您的情况下,您可以使用Joined Load,以便相关的行将加载到同一个查询中:
qry = (session.query(Employee).
options(joinedload(Employee.jobs)).
options(joinedload(Employee.roles))
).all()
如果您希望在加载Employee
时始终加载这些关系,则可以将relationship
配置为自动加载:
class Employee(Base):
# ...
jobs = relationship("EmployeeJob", lazy="joined")
roles = relationship("EmployeeRole", lazy="subquery")
2)只需创建一个从查询中提取数据结构的方法。下面的内容应该这样做(从答案的第一部分使用qry
):
def get_structure(qry):
res = [{"id": e.id,
"jobs": [j.id for j in e.jobs],
"roles": [[r.location_id, r.role_id] for r in e.roles],
}
for e in qry
]
return res
另请注意:您的EmployeeJob
表格有趣primary_key
,其中包含id
列和两个ForeignKey
列。我认为你应该选择其中一种。
答案 1 :(得分:0)
我终于找到了完成第二个问题的方法,并决定为了别人的利益回答我自己的问题:
from sqlalchemy.ext.hybrid import hybrid_property
class Employee(Base):
__tablename__ = "t_employee"
id = Column(Identifier(20), Sequence('%s_id_seq' % __tablename__), primary_key=True, nullable=False)
_jobs = relationship("EmployeeJob", lazy="joined", cascade="all, delete, delete-orphan")
_roles = relationship("EmployeeRole", lazy="joined", cascade="all, delete, delete-orphan")
@hybrid_property
def jobs(self):
return [item.employee_id for item in self._jobs]
@jobs.setter
def jobs(self, value):
self._jobs = [EmployeeJob(job_id=id) for id in value]
@hybrid_property
def roles(self):
return [[item.location_id, item.role_id] for item in self._roles]
@roles.setter
def roles(self, value):
self._roles = [EmployeeRole(location_id=l_id, role_id=r_id) for l_id, r_id in value]
关系中的级联是为了确保在更新列表后删除孤儿,并且装饰器定义每个复杂属性的getter和setter
感谢范指示我指向正确的方向!