繁体   English   中英

SQLAlchemy声明:如何合并模型和现有业务逻辑类

[英]SQLAlchemy Declarative: How to merge models and existing business logic classes

我想知道在业务逻辑代码中使用SQLALchemy声明性模型的最佳实践。 也许stackexchange.codereview可能是一个更好的地方问这个,但我不确定。

这是一些背景知识。

假设我有很多课程在做各种各样的事情。 它们中的大多数彼此很少或者没有任何关系。每个类都有一百到一千行代码,这些代码与数据库有很少的关系。 事实上,到目前为止,大多数类甚至都没有数据库感知。 我已经将实际信息存储在平面文件(csv,yaml等)中,并且只维护序列号表和文档路径 - 数据库中的序列号映射。 每个对象通过从数据库中获取正确的路径(按序列号)来检索所需的文件,并从那里重建自己。 到目前为止,这是非常方便的,因为我的“模型”已经(并且不可否认,仍然是)不仅仅是流动的。

当我扩展数据库在我目前拥有的代码库中的参与时,我似乎已经确定了以下模型,将数据库位和业务逻辑分成两个完全独立的部分,并使用特定的函数调用而不是继承来连接它们。甚至是作文。 这是我现在的代码类型的基本示例(伪代码质量):

模块/分贝/ models.py:

class Example(Base):
    id = Column(...)
    some_var = Column(...)

模块/分贝/ controller.py:

from .models import Example

def get_example_by_id(id, session):
    return session.query(Example).filter_by(id=id).one()

def upsert_example(id=None, some_var=None, session):
    if id is not None:
        try:
            example_obj = get_example_by_id(id, session)
            example_obj.some_var = some_var
            return
        except:
            pass
    example_obj = Example(some_var=some_var)
    session.add(example_obj)
    session.flush()

模块/ example.py:

from db import controller

class Example(object):
    def __init__(self, id):
        self._id = id
        self._some_var = None
        try:
            self._load_from_db()
            self._defined = True
        except:
            self._defined = False

    def _load_from_db(self, session):
        db_obj = controller.get_example_by_id(self._id, session)
        self._some_var = db_obj.some_var

    def create(some_var, session):
        if self._defined is True:
            raise Exception
        self._some_var = some_var
        self._sync_to_db(session)

    def _sync_to_db(self, session):
        controller.upsert_example(self._some_var, session)

    @property
    def some_var(self):
        return self._some_var

    ... 

我不相信这是要走的路。

我有几个模型遵循这种模式,还有更多我应该及时实现的模型。 该数据库目前仅用于持久性和归档。 一旦某些东西进入数据库,它或多或少只能从那里读取。但是,查询它变得越来越重要。

我倾向于从平面文件迁移到数据库的原因主要是为了提高可伸缩性。

到目前为止,如果我想找到带有some_var = 3的Example的所有实例(行),我必须从平面文件构造所有实例并迭代它们。 这似乎浪费了处理器时间和内存。 在许多情况下,some_var实际上是一个计算属性,并且使用平面文件中包含的源数据通过相当昂贵的过程来实现。

使用上面的结构,我要做的是查询Example,获取满足我的标准的id的列表,然后重新构建那些模块实例。

然而,正如我所理解的那样,ORM方法将使用厚模型,其中查询返回的对象本身就是我需要的对象。 我想知道尝试转向那种结构是否有意义。

为此,我有以下'问题'/想法:

  • 我的直觉是上面的代码片段反模式比它们是有用的模式更多。 我不能完全理解为什么,但我对此并不满意。 上面列出的结构是否存在真正的,有形的缺点? 在这种方法中,采用更多ORM-ish设计是否会提供功能/性能/可维护性方面的优势?

  • 关于将自己绑定到数据库模式我很偏执。 我对常规数据库迁移也很偏执。 上面列出的方法让我有一种安心,因为我知道如果我确实需要进行一些迁移,它将仅限于_load_from_db和_sync_to_db函数,并且让我不知所措地使用其余所有代码。

    • 我认为厚模型方法中的迁移成本很高我错了吗?
    • 我的安全感在限制我的代码的数据库参与更多是一种虚假的安全感而不是有用的分离?
  • 如果我想将module / db / models.py中的Example与上面示例中的module / example.py中的Example集成,那么最简单的方法是什么。 或者,使用SQLAlchemy处理业务逻辑重型模型的可接受模式是什么?

  • 在上面的代码中,请注意业务逻辑类将所有信息保存在“私有”实例变量中,而Model类将所有信息保存在类变量中。 如何整合这两种方法实际上有效? 从理论上讲,即使将它们组合在一个类定义中,它们仍然应该“正常工作”。 在实践中,是吗?

(实际的代码库在github上 ,虽然它不太可读)

我认为,即使我们正在研究它们,对我们自己的设计进行批评也是很自然的(至少对我而言)。 你在这里的结构对我来说似乎很好。 他们是否合适的答案取决于你打算做什么。

如果将代码整合到厚模型中,那么所有代码​​都将是一个位置,并且您的体系结构将更简单,但是,它也可能意味着您的业务逻辑将紧密绑定到数据库中创建的模式。 重新思考数据库意味着重新思考应用程序中其他区域的大部分内容。

遵循此处提供的代码示例意味着将具有负面影响的问题分开,例如更多地方的更多代码行和更高的复杂性,但这也意味着耦合更松散。 如果你保持正确,那么如果您决定更改数据库架构或转移到完全不同的存储形式,那么您应该会遇到更少的麻烦。 由于您的业务逻辑类是一个普通的旧对象,因此它可以作为一个很好的分离状态容器。 如果你转向其他东西,你仍然需要重新设计模型层和可能的部分控制器,但你的业务逻辑和UI层可能基本保持不变。

我认为真正的考验在于询问这个应用程序的规模有多大以及您计划在服务中使用多长时间? 如果我们正在寻找寿命短的小型应用,那么松散联轴器的复杂性增加是一种浪费,除非您是出于教育目的而这样做。 如果预计应用程序将变得非常大或已经使用多年,那么对复杂性的早期投资应该在较长时间内以较低的拥有成本得到回报,因为对各种组件的更改应该更容易。

如果它让你感觉更好,那么在使用ORM(例如实体框架和hybernate)时出于同样的原因,看POCO和POJO并不罕见。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM