gpt4 book ai didi

python - SQLAlchemy声明式: How to merge models and existing business logic classes

转载 作者:太空宇宙 更新时间:2023-11-03 10:59:58 25 4
gpt4 key购买 nike

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

这是一些背景。

假设我有一堆类来做各种事情。它们中的大多数彼此之间几乎没有关系或根本没有关系,每个此类都有一百到数千行代码来执行与数据库几乎没有关系的工作。实际上,到目前为止,大多数类甚至都不知道数据库。我已经将实际信息存储在平面文件(csv,yaml等)中,并且只维护了序列号表和文档路径-数据库中的序列号映射。每个对象都通过从数据库中获取正确的路径(按序列号)来检索所需的文件,并从那里重建自身。到目前为止,这已经非常方便了,因为我的“模型”已经(而且仍然会继续)不只是流动性。

当我扩大数据库在当前代码库中的参与范围时,我似乎已经决定采用以下模型,将数据库位和业务逻辑分为两个完全独立的部分,并使用特定的函数调用(而不是继承或继承)将它们合并甚至组成。这是我现在拥有的那种代码的基本示例(伪代码质量):

module/db/models.py:

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

module/db/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()

module/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的设计是否会在功能/性能/可维护性方面提供优势?
  • 我对将自己束缚于数据库模式感到疑惑。我也对常规的数据库迁移抱有偏执。上面列出的方法让我有些安心,因为如果我确实需要进行一些迁移,则它将仅限于_load_from_db和_sync_to_db函数,并且让我在所有其他代码中都混在一起。
  • 我对在“厚模型”方法中迁移的成本很高感到错了吗?
  • 我在限制代码的数据库参与方面的安全感是否更多是一种错误的安全感,而不是一种有用的分隔?
  • 如果我想在上面的示例中将来自module/db/models.py的Example与来自module/example.py的Example集成在一起,那将是最干净的方法。另外,使用SQLAlchemy处理业务逻辑繁重模型的可接受模式是什么?
  • 在上面的代码中,请注意,业务逻辑类将其所有信息保留在“私有(private)”实例变量中,而Model类将其所有信息保留在类变量中。整合这两种方法实际上将如何工作?从理论上讲,即使将它们放在单个类定义中,它们也仍然应该“正常工作”。实际上,是吗?

  • (实际的代码库位于 github上,尽管不太容易阅读)

    最佳答案

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

    如果将代码整合为厚实的模型,那么所有这些都将集中在一个地方,并且您的体系结构将更简单,但是,这也可能意味着您的业务逻辑将紧密地绑定(bind)到数据库中创建的模式。重新考虑数据库意味着重新考虑应用程序中其他大部分区域。

    遵循此处提供的代码示例意味着将关注点分离,这些关注点具有负面影响,例如在更多位置放置更多行代码并增加了复杂性,但这也意味着耦合较松散。如果保持不变,那么如果您决定更改数据库架构或转移到另一种完全不同的存储形式,则麻烦将大大减少。由于您的业务逻辑类是一个普通的旧对象,因此它可以作为一个很好的分离状态容器。如果转移到其他地方,您仍然必须重新设计模型层以及可能的 Controller 部分,但是您的业务逻辑和UI层可能在很大程度上保持不变。

    我认为真正的考验在于询问该应用程序的规模,以及您打算将其投入使用多长时间?如果我们正在寻找生命周期短的小型应用程序,那么除非您出于教育目的而这样做,否则增加了松散联轴器的复杂性,这是浪费。如果应用程序预计会变得很大或可以使用很多年,那么从长远来看,早期的复杂性投资应该以较低的拥有成本获得返回,因为对各个组件的更改应该更容易。

    如果让您感觉更好,出于相同的原因,在使用ORM(例如 Entity Framework )和hybernate时,经常会看到POCO和POJO。

    关于python - SQLAlchemy声明式: How to merge models and existing business logic classes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34866439/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com