1

我想检索查询的所有结果。我的代码如下所示:

engine = sqlalchemy.create_engine(...)
Base = declarative_base()
class Something(Base):
    ...
Session = sessionmaker(bind=engine)
session = Session()
query = session.query(Something).filter(...).all()

我明白了query.count() == 3000,但是当我尝试时results = query.all(),我只得到一行(即len(results) == 1)。

我的理解是query.all()执行查询并返回所有结果的列表。我在这里错过了什么吗?计算的行数大于返回的行数的一些可能原因是什么?

编辑(更多细节):

获取原始 SQL(例如查看str(query)并进行参数替换)并将其传递给它session.execute似乎工作得很好:

# this gives 3000 rows
for row in session.execute(raw_sql, {'param1': val1, 'param2': val2}):
    print(row)

解决方案

原来问题是我的主键不是唯一的。经验教训:设置课程时要非常小心!就我而言,我有:

class Something(Base):
    row_id_1 = Column(Integer, primary_key=True)
    row_id_2 = Column(Integer)  # PROBLEM! Need to specify primary_key=True
    value = Column(Float)

这会导致问题,因为主键是组合(row_id_1,row_id_2)。

4

1 回答 1

1

您的问题与您的主键不是唯一的事实有关。假设您的映射是...

class Something(Base):
    __tablename__ = 'things'

    id = Column(Integer, primary_key=True)
    name = Column(String(50))

您的数据库中有以下数据...

| ID| Name  |
| 1 | Larry |
| 1 | Moe   |
| 1 | Curly |

如果你这样做了...

SELECT * FROM names

你会得到三个结果。这就是executeSQLAlchemy 中的函数所做的。

然而,ORM 更进一步。当使用 ORM 查询“things”表时,将结果转化为Something对象。此外,他们由 SQLAlchemy 使用身份映射进行跟踪。将第一条记录(“Larry”)转换为对象后,它会查看第二条记录(“Moe”,ID 也是 1)。因为 1 的 ID 是完全一样的,所以假设记录和第一条记录代表的是同一个对象。因此,它不会实例化一个新Something对象,而只是移动到下一条记录。

文档

在最一般的意义上,Session 建立了与数据库的所有对话,并为您在其生命周期内加载或与之关联的所有对象代表了一个“保存区”。它提供了获取 Query 对象的入口点,该对象使用 Session 对象的当前数据库连接向数据库发送查询,将结果行填充到对象中,然后存储在 Session 中,在称为 Identity Map 的结构内 - 一种维护数据结构每个对象的唯一副本,其中“唯一”表示“只有一个具有特定主键的对象”。

“身份映射”是您看到此行为的原因。当你说主键是“ID”字段时,SQLAlchemy 会让你遵守这个承诺,如果它看到返回的多条记录具有相同的 ID,它会假定它们都是同一个对象。

确保您的主键是唯一的解决方案。

于 2013-10-16T18:47:35.513 回答