如何使用 SqlAlchemy 使用 ORM 从多值字段中获取对象列表?
How to get list of objects from multi-value field with SqlAlchemy using ORM?
我有来自客户的 MS Access 数据库文件 (.accdb),需要用 declarative_base class 描述 table 和列。正如我在 table 构造函数中看到的那样 - 其中一列具有 Integer 值并且与另一个 table (外键)中的另一列具有“一对多”关系。
但实际上在这个外键中存储的不是单个整数值,而是用分号分隔的数字值字符串。这种技术称为“多值字段”。事实上,这是“多对多”关系 without associative tables.
非常简化的方案:
Persons
-------------
id - Integer
name - String
vacancy_id - Integer (multi-value, Foreign key of Vacancies.id)
Vacancies
-------------
id - Integer
vacancy_name - String
我尝试使用 declarative_base 父 class 将 classes 映射到 tables。但是找不到如何在没有 关联table 的情况下声明“多对多”关系。现在我有了这样的代码。
Base = declarative_base()
class Vacancy(Base):
__tablename__ = 'Vacancies'
id = sa.Column(sa.Integer, name='id', primary_key=True, autoincrement=True)
vacancy_name = sa.Column(sa.String(255), name='vacancy_name')
class Person(Base):
__tablename__ = 'Persons'
id = sa.Column(sa.Integer, name='id', primary_key=True, autoincrement=True)
name = sa.Column(sa.String(255), name='name')
vacancy_id = sa.Column(sa.Integer, ForeignKey(Vacancy.id), name='vacancy_id')
vacancies = relationship(Vacancy)
在请求期间我有奇怪的行为:
- 如果未指定 vacancy_id,我会得到 Person.vacancies 作为 None。
- 如果 vacancy_id 指定为单个值(即“1”),在 Person.vacancies 中我得到空缺的单个对象 class.
- 如果 vacancy_id 指定为多个值(即“1;2;3”),在 Person.vacancies 我也得到 None.
当然,我可以请求原始 Person.vacancy_id,用分号将其分开,并请求获取带有 ID 列表的职位空缺。
但我想知道 - SqlAlchemy 是否可以处理“多值字段”?处理此类文件的最佳方式是什么?
更新
目前我做了以下解决方法来自动解析多值列。这应该添加到 Persons class:
@orm.reconstructor
def load_on_init(self):
if self.vacancy_id:
ids = self.vacancy_id.split(';')
self.vacancies = [x for x in Vacancy.query.filter(Vacancy.id.in_(ids)).all()]
else:
self.vacancies = []
职位空缺class 应具有以下属性:
query = DBSession.query_property()
最后我们必须为 in-class 用法准备会话:
engine = create_engine(CONNECTION_URI)
DBSession = scoped_session(sessionmaker(bind=engine))
Base = declarative_base()
Access ODBC 对多值查找字段提供非常有限的支持。此类字段实际上是使用隐藏关联 table(名称如 f_1BC9E55B5578456EB5ACABC99BB2FF0B_vacancies
)实现的,但这些 table 无法从 SQL 语句访问:
SELECT * from f_1BC9E55B5578456EB5ACABC99BB2FF0B_vacancies
导致错误
The Microsoft Access database engine cannot find the input table or query ''. Make sure it exists and that its name is spelled correctly.
如您所见,Access ODBC 将读取 多个条目的键值并将它们呈现为我们可以解析的分号分隔列表,但我们无法更新这些值
UPDATE Persons SET vacancies = '1;2' WHERE id = 1
失败
An UPDATE or DELETE query cannot contain a multi-valued field. (-3209)
所以,TL;DR,如果您只需要从数据库中读取,那么您的解决方法可能就足够了,但是如果您需要修改那些多值字段,那么 Access ODBC 将无法完成你.
我有来自客户的 MS Access 数据库文件 (.accdb),需要用 declarative_base class 描述 table 和列。正如我在 table 构造函数中看到的那样 - 其中一列具有 Integer 值并且与另一个 table (外键)中的另一列具有“一对多”关系。 但实际上在这个外键中存储的不是单个整数值,而是用分号分隔的数字值字符串。这种技术称为“多值字段”。事实上,这是“多对多”关系 without associative tables.
非常简化的方案:
Persons
-------------
id - Integer
name - String
vacancy_id - Integer (multi-value, Foreign key of Vacancies.id)
Vacancies
-------------
id - Integer
vacancy_name - String
我尝试使用 declarative_base 父 class 将 classes 映射到 tables。但是找不到如何在没有 关联table 的情况下声明“多对多”关系。现在我有了这样的代码。
Base = declarative_base()
class Vacancy(Base):
__tablename__ = 'Vacancies'
id = sa.Column(sa.Integer, name='id', primary_key=True, autoincrement=True)
vacancy_name = sa.Column(sa.String(255), name='vacancy_name')
class Person(Base):
__tablename__ = 'Persons'
id = sa.Column(sa.Integer, name='id', primary_key=True, autoincrement=True)
name = sa.Column(sa.String(255), name='name')
vacancy_id = sa.Column(sa.Integer, ForeignKey(Vacancy.id), name='vacancy_id')
vacancies = relationship(Vacancy)
在请求期间我有奇怪的行为:
- 如果未指定 vacancy_id,我会得到 Person.vacancies 作为 None。
- 如果 vacancy_id 指定为单个值(即“1”),在 Person.vacancies 中我得到空缺的单个对象 class.
- 如果 vacancy_id 指定为多个值(即“1;2;3”),在 Person.vacancies 我也得到 None.
当然,我可以请求原始 Person.vacancy_id,用分号将其分开,并请求获取带有 ID 列表的职位空缺。
但我想知道 - SqlAlchemy 是否可以处理“多值字段”?处理此类文件的最佳方式是什么?
更新 目前我做了以下解决方法来自动解析多值列。这应该添加到 Persons class:
@orm.reconstructor
def load_on_init(self):
if self.vacancy_id:
ids = self.vacancy_id.split(';')
self.vacancies = [x for x in Vacancy.query.filter(Vacancy.id.in_(ids)).all()]
else:
self.vacancies = []
职位空缺class 应具有以下属性:
query = DBSession.query_property()
最后我们必须为 in-class 用法准备会话:
engine = create_engine(CONNECTION_URI)
DBSession = scoped_session(sessionmaker(bind=engine))
Base = declarative_base()
Access ODBC 对多值查找字段提供非常有限的支持。此类字段实际上是使用隐藏关联 table(名称如 f_1BC9E55B5578456EB5ACABC99BB2FF0B_vacancies
)实现的,但这些 table 无法从 SQL 语句访问:
SELECT * from f_1BC9E55B5578456EB5ACABC99BB2FF0B_vacancies
导致错误
The Microsoft Access database engine cannot find the input table or query ''. Make sure it exists and that its name is spelled correctly.
如您所见,Access ODBC 将读取 多个条目的键值并将它们呈现为我们可以解析的分号分隔列表,但我们无法更新这些值
UPDATE Persons SET vacancies = '1;2' WHERE id = 1
失败
An UPDATE or DELETE query cannot contain a multi-valued field. (-3209)
所以,TL;DR,如果您只需要从数据库中读取,那么您的解决方法可能就足够了,但是如果您需要修改那些多值字段,那么 Access ODBC 将无法完成你.