有谁能帮我理解以下行为?我有一个简单的架构,其中一个项目有许多资产和元素。资产和要素在项目范围内具有多对多关系。
我需要确保一个Element有一个在Project范围内唯一的代码,所以在我向SQLAlchemy会话添加一个新元素之前,我想检查一个具有相同代码的Element是否已经存在在项目中。我发现,当我使用关联表来映射元素和资产之间的多对多关系时,如果没有查询操作实际将新元素提交给数据库,我就无法查询数据库。
要明确的是,此时我还没有添加'ed或提交'这个新元素到SQLAlchemy会话。
from sqlalchemy import create_engine, and_
from sqlalchemy import Table, Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker, relation, backref
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
### your credentials here ###
# _MYSQL_DB =
# _MYSQL_USER =
# _MYSQL_PWORD =
# _MYSQL_SCHEMATA =
# _MYSQL_TEST_SCHEMATA =
testEngine = create_engine("mysql://%s:%s@%s/%s"%( _MYSQL_USER,
_MYSQL_PWORD,
_MYSQL_DB,
_MYSQL_TEST_SCHEMATA),
pool_recycle=3600,
echo=True)
Base = declarative_base()
SQLAlchemySession = sessionmaker(autoflush=True, autocommit=False)
class Project(Base):
__tablename__ = "SA_project_t"
id = Column(Integer, primary_key=True, autoincrement=True)
code = Column(String(24), nullable=False, unique=True)
class Asset(Base):
__tablename__ = "SA_asset_t"
id = Column(Integer, primary_key=True, autoincrement=True)
projectId = Column(Integer, ForeignKey("SA_project_t.id"))
project = relation("Project")
code = Column(String(128))
element_to_asset_assoc = Table( "SA_elementToAssetAssoc_t",
Base.metadata,
Column("elementId", Integer, ForeignKey("SA_element_t.id")),
Column("assetId", Integer, ForeignKey("SA_asset_t.id")))
class Element(Base):
__tablename__ = "SA_element_t"
id = Column(Integer, primary_key=True, autoincrement=True)
projectId = Column(Integer, ForeignKey("SA_project_t.id"))
project = relation("Project")
code = Column(String(256))
assets = relation("Asset", secondary=element_to_asset_assoc, backref="elements")
Base.metadata.bind=testEngine
session = SQLAlchemySession(bind=testEngine)
Base.metadata.drop_all(checkfirst=True)
Base.metadata.create_all(testEngine, checkfirst=True)
# Create a Project, Asset and Element
project = Project()
project.code = "MyProject"
session.add(project)
asset = Asset()
asset.project = project
asset.code = "MyAsset"
session.add(asset)
element = Element()
element.project = project
element.code = "MyElement"
element.assets = [asset]
session.add(element)
session.commit()
# Now I'd like to add a new element, but first check that the
# element's code is unique within the scope of the Project
newElement = Element()
newElement.project = project
newElement.code = "MyElement"
newElement.assets = [asset]
results = session.query(Element).filter(and_( Element.project==newElement.project,
Element.code==newElement.code))
# Up until this point, newElement hasn't been inserted into the
# database, but once I query "results.count()" I find that an INSERT
# has been perfomed.
print results.count()
# p.s. I realize that results will contain both the original and
# new element, but I don't expect the new element to have been
# inserted into the database at this point.
在结果变量上调用 count()的操作是将 newElement 提交到MySQL数据库,这不是我的意图。如果我删除关联表,那么我会得到我期望的行为 - newElement 不会添加到数据库中。
从日志中我可以看到,会话在查询开始时将关联的资产视为脏,并且刷新它会触发 newElement 的提交。这是预期的行为吗?如果是这样,有没有办法保持多对多关系,同时仍然在这些情况下查询数据库,不触发提交。
使用SQLAlchemy 0.7.4
答案 0 :(得分:1)
不需要add()
newElement
对象,因为当您将绑定对象分配给其中一个关系时,它会自动添加到会话中。访问newElement.project
属性时,它会刷新到数据库(您可以使用autoflush=False
禁用此行为)。 MySQL默认使用MyISAM引擎,忽略事务语句。因此,所有刷新的变化都会持续存在。要启用事务支持,请将__table_args__ = {'mysql_engine': 'InnoDB'}
添加到映射的类中。