SQLAlchemy:成功插入但随后引发异常

时间:2014-04-04 14:28:19

标签: python sqlalchemy firebird fdb

我正在对FirebirdSQL运行SQLAlchemy,当我在项目中执行insert命令时,SQLAlchemy在从连接执行返回时引发异常。 但是,正在构建insert查询并成功执行。查询数据库显示项目实际上正在正确插入。

修改:我现在正在深入研究fbcore.py模块,检查valuevartype的值表明问题可能是怎样的用于生成主键ID的SEQUENCE项目返回其数据存在争议。 vartypeSQL_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 即可。这对我来说也很困惑。

2 个答案:

答案 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所示)。