使用字典作为预查询参数

19 阅读2分钟

如何将字典作为预查询参数进行绑定?我想将一个字典绑定到预查询语句的参数上,但我似乎无法弄清楚语法。让我困惑的是,如果我在没有预查询语句的情况下使用位置参数,它是可以工作的。

请看这个例子:

from cassandra.cluster import Cluster

def works():
    id = '1'
    mydict = {'count': 1, 'value': 3}

    updateStmt = "insert into test.prep_test (id, mydict) values (%s, %s);"

    session.execute(updateStmt, (id, mydict))


def doesntwork():
    id = '2'
    mydict = {'count': 1, 'value': 3}

    updateStmt = "insert into test.prep_test (id, mydict) values (?, ?);"
    prep = session.prepare(updateStmt)

    session.execute(prep, [id, mydict])


if __name__ == "__main__":
    cluster = Cluster(['127.0.0.1'])
    session = cluster.connect('test')

    session.execute(
        'create table if not exists test.prep_test (  id ascii, mydict MAP<ascii,decimal>, PRIMARY KEY (id));')

    works()
    doesntwork()

    session.shutdown()
    cluster.shutdown()

works() 方法可以正常插入数据。然而,doesntwork() 方法失败,并出现以下错误:

Traceback (most recent call last):
  File "/new.py", line 31, in <module>
    doesntwork()
  File "/new.py", line 20, in doesntwork
    session.execute(prep, [id, mydict])
  File "cassandra/cluster.py", line 1569, in cassandra.cluster.Session.execute (cassandra/cluster.c:26912)
  File "cassandra/cluster.py", line 1619, in cassandra.cluster.Session.execute_async (cassandra/cluster.c:27219)
  File "cassandra/cluster.py", line 1632, in cassandra.cluster.Session._create_response_future (cassandra/cluster.c:27553)
  File "cassandra/query.py", line 411, in cassandra.query.PreparedStatement.bind (cassandra/query.c:5947)
  File "cassandra/query.py", line 536, in cassandra.query.BoundStatement.bind (cassandra/query.c:7678)
TypeError: Received an argument of invalid type for column "mydict". Expected: <class 'cassandra.io.asyncorereactor.MapType(AsciiType, DecimalType)'>, Got: <type 'dict'>; (Non-Decimal type received for Decimal value)

Process finished with exit code 1

解决方案

当你在 works() 的情况下运行它时,驱动程序在幕后使用字符串替换来生成以下查询,并将其提交给 Cassandra:

insert into test.prep_test1 (id, mydict) values ('1', {'count': 1, 'value': 3});

这基本上是一个愚蠢的字符串替换。 在第二种情况下,服务器和客户端之间传递了多条消息。首先,准备了一条语句。关于此准备语句的上下文与 Cassandra 服务器共享。这里的验证将更加严格,因为与查询关联的上下文是驱动程序和服务器已知的。

你可以通过在查询中使用适当的类型来解决此问题,对于这个案例,将 mydict 绑定到 Decimal 值就是合适的。

mydict = {'count': Decimal(1), 'value': Decimal(3)}

或者,你可以在你的表中使用一个 int 类型,如下所示。

'create table if not exists test.prep_test (  id ascii, mydict MAP<ascii,int>, PRIMARY KEY (id));'

你可以辩称,驱动程序应该能够将 int 或 float 类型映射到 Decimal,但这并不是现在的工作方式。