首页 文章

Flask SQLAlchemy数据映射器与活动记录模式

提问于
浏览
11

我最近开始研究Flask和Flask-SQLAlchemy . 来自Django背景我发现Flask-SQLAlchmey非常复杂 . 我已经读过,SQLAlchemy实现了Data Mapper模式,而Django ORM则基于Active Record Pattern .

Here是编写的示例代码,用于实现访问数据库的存储库模式 .

Here是S.Lott(271k声誉)评论的另一个链接,他说ORM是数据访问层,它与模型分开 .

我的问题是这些:

  • 您是否可以在上面的示例中提供实际用例或您自己的数据映射器模式有用的示例?我读到的每个地方都是数据映射器模式在复杂情况下很有用,但没有看到示例 .

  • 在上述情况下使用存储库模式与使用数据映射器模式相同吗?

  • 数据映射器拥护者是否在与示例中所做的模型不同的类中编写选择查询?

  • 为什么 Question.query.filter_by(text = text).all() 不比 db.session.query(Question).filter(Question.text == text).all() 更好用?

这不是DataMapper vs ActiveRecord pattern的重复,因为这只是告诉定义,我对实际例子更感兴趣 .

2 回答

  • 3

    一点一点地说 .

    1.

    我有一个遗留数据库,我必须编写一些数据处理实用程序 . 使用Mapper模式,没有ORM / ActiveRecord样式,在编写像ActiveRecord那样的查询时,对我来说简单易行 . 它运行在类似于SQL子句的良好可组合对象上,不受SQL注入的影响 .

    被动对象允许更多的灵活性/统一性:复杂连接的结果是一个命名元组,这是简单选择的结果 . 没有任何标识可以关注,没有具有相同标识的缓存对象 .

    所有更新都是明确的;不是"save"某些状态在其他地方被改变,没有挂钩在 .save() 上运行等 . 这使得高效的批量更新变得微不足道,如果将正确的数据发送到数据库则不会有麻烦 . 两者都是我的好处 . 一般情况下,'it depends' . 例如,我必须在插入后手动获取数据库生成的ID . 显式运行此查询是一项额外的工作 . 能够在一个查询中执行此操作而不是每个记录一个,这对我来说是一个巨大的好处 .

    SQLAlchemy具有分层设计,允许您访问较低的“映射器”级别,即使您在ORM级别上声明事物并且通常对其进行操作也是如此 . 例如,在Django中,如果/仍然可能的话,它并不那么简单 .

    2.

    在该示例中,'repository'看起来像是在'mapper'之上构建的级别 . 存储库可以构建在纯DBAPI之上,但映射器使一些事情更简单,例如更好的参数绑定,结果集的命名元组,以及带有可组合,可重用部分的纯SQL之上的包装器 .

    映射器还提供一定程度的数据库独立性 . 例如 . SQL Server和Postgres有不同的方法来连接字符串;映射器提供统一的接口 .

    3.

    你在你使用它的地方写下了 select . 如果您有一个在不同上下文中不断重用的选择,则可以将其放入方法或函数中 . 大多数选择都有一个用途,并在现场 Build .

    SQLAlchemy设计的一个很好的特性是,您可以轻松地存储条件和整个 where 子句,并在select / update / delete语句中重用它们 .

    4.

    Question.query.filter_by(text = text).all() 使用隐式事务 . db.session.query(Question).filter(Question.text == text).all() 使用显式事务 .

    明确的交易让您高枕无忧 . 当您查询快速变化的数据库并希望您的几个相关的 select 看到相同的一致状态时,它们对于 select 也很重要 .

    我通常在 sessionmaker 周围写一个简单的包装器并写下这样的东西:

    with my_database.transaction() as trans:
       records = trans.query(...)
       ...
       updated = trans.execute(...).rowcount
    # Here the transaction commits if all went well.
    

    当我确定不知道DML应该在这个块中运行时,我会使用始终回滚的 .readonly_transaction() .

    在许多情况下,隐式交易很好 . Django允许您使用 @transaction.atomic 装饰方法并具有半显式事务控制,在99%的情况下足够 . 但有时你需要更精细的粒度 .

  • 2

    完全同意上面的答案:是的,SQLAlchemy的Data Mapper模式真的更灵活,对于复杂的查询,它真的更强大,更不神奇,更有控制 .

    但是,在诸如CRUD之类的简单任务中,SQLAlchemy的代码变得过于过重/过度/冗余 .

    对于例如,要在最简单的“创建”控制器中创建一些对象,您需要这样的东西:

    user = User(name='Nick', surname='Nickson')
    session.add(user)
    session.flush()
    

    在Active Record ORM中,您只需要单个字符串 .

    好吧, for simple tasks ,我们中的一些人可能想要更简单的东西 . 我的意思是拥有SQLAlchemy的Active Record会很酷 .

    好消息:我最近为此创建了包(它还包含其他有用的东西) .

    看看:https://github.com/absent1706/sqlalchemy-mixins

相关问题