Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sqlalchemy SQAlchemy具有复合主键的自定义辅助关系_Sqlalchemy - Fatal编程技术网

Sqlalchemy SQAlchemy具有复合主键的自定义辅助关系

Sqlalchemy SQAlchemy具有复合主键的自定义辅助关系,sqlalchemy,Sqlalchemy,共有3个表:帐户,角色,用户。Role和User都有一个指向account的外键account\u id 一个用户可以有多个角色,因此roles\u users表充当Role和user之间的辅助关系表 Account表是我们应用程序的租户表,用于分隔不同的客户 请注意,所有表(除了Account)都有带有Account\u id的复合主键。这样做有几个原因,但假设这样做是为了保持所有内容的一致性 现在,如果我有一个简单的二级关系(User.roles——被注释掉的关系),那么所有的关系都可以正常

共有3个表:
帐户
角色
用户
Role
User
都有一个指向
account
的外键
account\u id

一个用户可以有多个角色,因此
roles\u users
表充当
Role
user
之间的辅助关系表

Account
表是我们应用程序的租户表,用于分隔不同的客户

请注意,所有表(除了
Account
)都有带有
Account\u id
的复合主键。这样做有几个原因,但假设这样做是为了保持所有内容的一致性

现在,如果我有一个简单的二级关系(
User.roles
——被注释掉的关系),那么所有的关系都可以正常工作。嗯,有点。。它抛出了一个合理的警告(尽管我认为这应该是一个错误):

这就是为什么我创建了第二个关系
User.roles
——一个没有被注释掉的关系。查询按预期工作,其中有两个关于连接和所有内容的条件。但是,当我尝试在用户上保存某些角色时,会出现此错误:

sqlalchemy.orm.exc.UnmappedColumnError: Can't execute sync rule for source column 'roles_users.role_id'; mapper 'Mapper|User|user' does not map this column.  Try using an explicit `foreign_keys` collection which does not include destination column 'role.id' (or use a viewonly=True relation).
据我所知,SA无法确定如何保存次节点,因为它有一个自定义的
primaryjoin
secondaryjoin
,因此它建议使用
viewonly=True
,其效果是在保存模型时忽略角色关系

问题是如何为用户保存角色而不必手动完成(示例在代码中注释掉)。在真正的应用程序中,我们有许多次要关系,我们在许多地方保存它们。要把它们全部重写是非常困难的

是否有一种解决方案可以在保留下面的自定义
primaryjoin
secondaryjoin
的同时继续使用
User.roles=some_roles

使用SA 1.1.9的完整示例:

从sqlalchemy导入创建引擎、列、整数、文本、表、ForeignKeyConstraint、ForeignKey和_
从sqlalchemy.ext.declarative导入声明性基础
从sqlalchemy.orm导入外部、关系、会话
Base=声明性_Base()
类别帐户(基本):
__tablename_uuu='account'
id=列(整数,主键=True)
角色\用户=表(
“角色\用户”,Base.metadata,
列('account\u id',Integer,primary\u key=True),
列('user\u id',Integer,primary\u key=True),
列('role\u id',Integer,primary\u key=True),
ForeignKeyConstraint(['user\u id'、'account\u id']、['user.id'、'user.account\u id']),
ForeignKeyConstraint(['role\u id','account\u id'],['role.id','role.account\u id']),
)
类角色(基本):
__tablename_uu='role'
id=列(整数,主键=True)
account\u id=列(整数,ForeignKey('account.id'),primary\u key=True)
名称=列(文本)
定义(自我):
返回“”。格式(self.id,self.name)
类用户(基本):
__tablename_uu='user'
id=列(整数,主键=True)
account\u id=列(整数,ForeignKey('account.id'),primary\u key=True)
名称=列(文本)
#这与预期的一样:它将数据保存在用户的角色中
#角色=关系(角色,次要=角色\用户)
#此自定义关系-无效
角色=关系(
角色
次要=角色\用户,
primaryjoin=和u(外部(Role.id)=roles\u users.c.Role\u id,
Role.account\u id==roles\u users.c.account\u id),
secondaryjoin=和u(外部(id)=角色_users.c.user\u id,
account\u id==角色(用户.c.account\u id))
引擎=创建引擎('sqlite://'))
Base.metadata.create_all(引擎)
会话=会话(引擎)
#创建我们的帐户
a=账户()
会议.添加(a)
session.commit()
#创建2个角色
u_role=role()
u_role.id=1
u_角色.帐户_id=a.id
u_role.name='user'
会话.添加(u_角色)
m_role=角色()
m_role.id=2
m_role.account_id=a.id
m_role.name='member'
会话.添加(m_角色)
session.commit()
#创建1个用户
u=用户()
u、 id=1
u、 账户id=a.id
u、 名称='用户'
#这行不通
u、 角色=[u_角色,m_角色]
会话.添加(u)
session.commit()
#工作如期进行
i=角色\用户。插入()
i=i.值([
dict(帐户id=a.id,角色id=u\u角色id,用户id=u.id),
dict(帐户id=a.id,角色id=m\u角色id,用户id=u.id),
])
会话执行(i)
#从数据库中重新获取用户
u=session.query(User.first)()
对于担任美国职务的r:
印刷品(r)

注意:使用
secondaryjoin
切换
primaryjoin
没有帮助

为后代着想的解决方案-切换外部包装并小心主连接与次连接:

与此相反:

角色=关系(
角色
次要=角色\用户,
primaryjoin=和u(外部(Role.id)=roles\u users.c.Role\u id,
Role.account\u id==roles\u users.c.account\u id),
secondaryjoin=和u(外部(id)=角色_users.c.user\u id,
account\u id==角色(用户.c.account\u id))
这样做:


角色=关系(
角色
次要=角色\用户,
primaryjoin=和(id==外部(角色)用户(c.user)用户(id),帐户(id==外部(角色)用户(c.account)用户(id),,
secondaryjoin=和(Role.id==外部(roles\u users.c.Role\u id),Role.account\u id==roles\u users.c.account\u id),
)
sqlalchemy.orm.exc.UnmappedColumnError: Can't execute sync rule for source column 'roles_users.role_id'; mapper 'Mapper|User|user' does not map this column.  Try using an explicit `foreign_keys` collection which does not include destination column 'role.id' (or use a viewonly=True relation).