这是一个相当长的帖子,所以我把它分为主要问题,一个有代码的说明性示例,最后还描述了我的想法和问题。在
我在整个应用程序中使用分离的实体。这是向应用程序的其余部分公开ORM实体的正确方法吗?如果没有,有什么问题?在
数据库设置:
db_conn_string = "sqlite://"
# db_conn_string = "mysql+pymysql://root:root@33.33.33.1:33060/alchemist"
engine = create_engine(db_conn_string)
Base.metadata.bind = engine
DBSession = sessionmaker(bind=engine, expire_on_commit=False)
对于实体,我只定义关系,如果我急于加载它们。这是为了确保当它们被用作分离的实体时,不能直接检索未加载的相关实体。在
实体(截断):
^{pr2}$我提供了一个repository对象来执行基本的CRUD操作。然后在存储库周围的上下文对象中管理会话事务范围:
class RepositoryContext(object):
def __init__(self, entity_class):
self.entity_class = entity_class
def __enter__(self):
self.session = get_session()
return CrudRepository(self.entity_class, self.session)
def __exit__(self, exc_type, exc_val, exc_tb):
try:
self.session.commit()
except Exception:
self.session.rollback()
raise
finally:
self.session.close()
class CrudRepository(object):
"""
CrudRepository implements (entity agnostic) CRUD operations.
"""
def __init__(self, entity_class, session):
self.entity_class = entity_class
self._session = session
def retrieve_all(self):
return self._session.query(self.entity_class).all()
def retrieve_by(self, **kwargs):
return self._session.query(self.entity_class).filter_by(**kwargs).one_or_none()
# Other CRUD methods here.
def query(self):
'''To perform custom queries'''
return self._session.query(self.entity_class)
所以基本用法如下:
with RepositoryContext(Tree) as repo:
tree = repo.retrieve_by(id=1)
# Session is closed outside of context. tree is a detached instance.
len(tree.branches) # This is ok, eager loaded
如果您想获得某个分支的叶子,我们不能使用tree.branches[0].leaves
来访问它,因为没有定义该关系。因为我们不想急于加载它,我们必须单独检索它,如下所示:
with RepositoryContext(Leaf) as repo:
branch = tree.branches[0]
leaves = repo.query().filter_by(branch_id=branch.id).all()
# Now have leaves related to first branch. Also detached
同样,对于更新或刷新,您需要打开一个上下文并调用相关函数:
with RepositoryContext(Tree) as repo:
repo.refresh(tree) # This refreshes the tree state (discarding changes)
对于一个新项目,我们正在使用sqlalchemyorm,但我不确定如何正确地使用ORM实体。在
我一直被教导域模型和数据库细节应该尽可能地相互分离。然而,对于ORM,这意味着我必须不断地将ORM实体映射到领域模型对象,然后再映射回来,这就破坏了使用ORM的全部意义。在
在应用程序中使用ORM实体的过程中,我想确保不会产生意外的副作用。因此,我创建了一个严格的事务作用域,以强制任何持久性都由存储库类显式处理。这意味着我在整个应用程序中使用分离的实体,并且只在事务中附加它们。在
在我当前的实现中,我失去了SQLAlchemy提供的一些功能。即访问尚未预先加载的相关数据(例如,在代码示例中:branch.leaves
未定义,因此您必须通过指定分支id来添加它们)。在
很抱歉,如果这篇文章很长,我已经尽可能多的删节,同时保持它的运行。在
对于那些正在寻找更多信息/指导方针的人:mikebayer在https://groups.google.com/forum/#!topic/sqlalchemy/u9Igta1CYdo上写了一篇非常详细的回答。在
相关问题 更多 >
编程相关推荐