我正在对FirebirdSQL运行SQLAlchemy,当我在项目中执行insert
命令时,SQLAlchemy在从连接执行返回时引发异常。 但是,正在构建insert
查询并成功执行。查询数据库显示项目实际上正在正确插入。
修改:我现在正在深入研究fbcore.py
模块,检查value
和vartype
的值表明问题可能是怎样的用于生成主键ID的SEQUENCE
项目返回其数据存在争议。 vartype
为SQL_LONG
,但实际值为[<an integer>]
,其中<an integer>
是我为自动增加主键而创建的序列生成器返回的值(例如[14]
1}})。这告诉我,应该通过修复 来解决问题,尽管我不知道该怎么做。生成器似乎在数据库本身内正常工作,但在返回SQLAlchemy时会导致问题。
有关详细信息,请参阅下面的现有实现和堆栈跟踪。
我的代码:
class Project:
# (I've snipped project instantiation, where engine connection, table, etc. are configured)
def save_project(self, id_=None, title=None, file_name=None, file_location=None):
# Build the dictionary of values to store
values = {}
if title is not None:
values['title'] = title
if file_name is not None:
values['file_name'] = file_name
if file_location is not None:
values['file_location'] = file_location
# Simplification: I account for the case that there *is* data---skipping that here
# Execute the correct kind of statement: insert or settings_update.
if id_ is None:
statement = self.table.insert()
else:
statement = self.table.update().where(self.table.c.id == id_)
result = self.connection.execute(statement, values)
# If we inserted a row, get the new primary key. Otherwise, return
# the one specified by the user; it does not change on settings_update.
project_id = result.inserted_primary_key if result.is_insert else id_
追溯:
File "/Users/chris/development/quest/workspace/my_project/data/tables.py", line 350, in save_project
result = self.connection.execute(statement, values)
File "/Users/chris/.virtualenvs/my_project/lib/python3.3/site-packages/sqlalchemy/engine/base.py", line 720, in execute
return meth(self, multiparams, params)
File "/Users/chris/.virtualenvs/my_project/lib/python3.3/site-packages/sqlalchemy/sql/elements.py", line 317, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/Users/chris/.virtualenvs/my_project/lib/python3.3/site-packages/sqlalchemy/engine/base.py", line 817, in _execute_clauseelement
compiled_sql, distilled_params
File "/Users/chris/.virtualenvs/my_project/lib/python3.3/site-packages/sqlalchemy/engine/base.py", line 947, in _execute_context
context)
File "/Users/chris/.virtualenvs/my_project/lib/python3.3/site-packages/sqlalchemy/engine/base.py", line 1111, in _handle_dbapi_exception
util.reraise(*exc_info)
File "/Users/chris/.virtualenvs/my_project/lib/python3.3/site-packages/sqlalchemy/util/compat.py", line 168, in reraise
raise value
File "/Users/chris/.virtualenvs/my_project/lib/python3.3/site-packages/sqlalchemy/engine/base.py", line 940, in _execute_context
context)
File "/Users/chris/.virtualenvs/my_project/lib/python3.3/site-packages/sqlalchemy/dialects/firebird/kinterbasdb.py", line 106, in do_execute
cursor.execute(statement, parameters or [])
File "/Users/chris/.virtualenvs/my_project/lib/python3.3/site-packages/fdb/fbcore.py", line 3323, in execute
self._ps._execute(parameters)
File "/Users/chris/.virtualenvs/my_project/lib/python3.3/site-packages/fdb/fbcore.py", line 2991, in _execute
self.__Tuple2XSQLDA(self._in_sqlda, parameters)
File "/Users/chris/.virtualenvs/my_project/lib/python3.3/site-packages/fdb/fbcore.py", line 2782, in __Tuple2XSQLDA
sqlvar.sqlscale)
File "/Users/chris/.virtualenvs/my_project/lib/python3.3/site-packages/fdb/fbcore.py", line 2266, in _check_integer_range
if (value < vmin) or (value > vmax):
TypeError: unorderable types: list() < int()
我还不熟悉SQLAlchemy,看看为什么这是一个问题;我的陈述风格与tutorial中的风格非常相似。这似乎是如何传递参数的问题 - 可能是关于使用dict而不是关键字参数的问题?但是docs中没有关于如何处理参数的信息,这表明我在这里有任何不妥之处 - 看起来就像我在那看到的那样。
我也尝试使用self.table.insert().values(values)
,而不是将values
术语传递给execute
方法,结果相同(正如我所料)。
编辑:我在阅读execute
fbcore.py
上的文档字符串时注意到,当传递给方法的参数未作为列表或列表提供时,它会引发TypeError一个元组。这是一个尚未在文档中反映出来的变化吗?
编辑2:作为a comment注释,堆栈跟踪表明它正在针对 kinterbasdb 驱动程序运行,尽管我已明确配置引擎以使用的 FDB 即可。这对我来说也很困惑。
答案 0 :(得分:3)
正如我可能预期的那样,特别是一旦我发现问题是该行按预期插入但随后不久用UPDATE
函数调用,问题就是一些相关的代码。我将结果返回为project_id
(正如您在上面的代码中看到的那样),并且由于完全不相关的原因(与Blinker信号有关),该方法再次被调用,返回值为{{ 1}},这是我设定的:
project_id
此行的正确版本略有不同:
project_id = result.inserted_primary_key if result.is_insert else id_
来自the SQLAlchemy docs(强调我的):
返回刚刚插入的行的主键。
返回值是 标量值列表 ,对应于目标表中的主键列列表。
此处的返回值必须是列表,因为主键可以是数据库中多个字段的组合。 (这对我来说应该是显而易见的;很明显我在一年多的时间里没有做过严肃的数据库工作。)由于这种情况下的主键是单个值,我只是选择了该值并将其返回,问题是解决。
当然,现在我必须去追捕那个Blinker信号问题 - 这个方法不应该被调用两次 - 但是不要过来......
答案 1 :(得分:1)
我一直在查看SQL Alchemy文档,我想知道你是否应该这样做:
if id_ is None:
statement = self.table.insert()
else:
statement = self.table.update().where(self.table.c.id == id_)
statement = statement.values(title=title, file_name=file_name, file_location=file_location)
result = self.connection.execute(statement)
即:不是将字典传递给执行,而是将其作为语句的一部分(如Insert Expressions所示)。