2

实际上,我正在使用 python 3.4 为桌面设计一个大型应用程序。我选择了端口和适配器架构,即六边形架构。它的主要目的是使用可重用的组件。

为了组织代码并制定一些规则,我们将使用 Zope 组件架构 (ZCA)

所以要做一些 POC,我正在创建数据库组件。但是使用 ORM 的事实阻止了我。我的意思是我设计了一些看起来像的数据库组件:

-IDatabase -IDatabaseConfig -IEntity -IKey -IReader -IWriter ... 和实现。

SQLAlchemy 管理很多东西,我不知道如何使我的组件可重用。

我找到了这段代码:

#Reflect each database table we need to use, using metadata
class Customer(Base):
    __table__ = Table('Customers', metadata, autoload=True)
    orders = relationship("Order", backref="customer")

class Shipper(Base):
    __table__ = Table('Shippers', metadata, autoload=True)
    orders = relationship("Order", backref="shipper")

class Product(Base):
    __table__ = Table('Products', metadata, autoload=True)
    supplier = relationship('Supplier', backref='products')
    category = relationship('Category', backref='products') 

但我猜这段代码真的很难与 SQLAlchemy 耦合。那么我应该在我的架构中使用什么方法呢?

由于实体必须是应用程序的中心(域层),如果我需要更改我的数据库组件并且不使用 SQLAlchemy,那么该解决方案会出现问题吗?

我愿意接受所有建议。

4

1 回答 1

0

我使用 ORM 作为实体对象并将适配器放在它上面:

在 API 的某处interfaces.py定义:

from zope.interface import Interface

class IEntity(Interface):

    def pi_ing():
        '''makes the entity go "pi-ing" '''

某处定义了数据库模型:

class EntityA(Base):       
    # .. table and relationship definitions are here

在其他地方实现了 API:

from zope.interface import implementer
from zope.component import adapter, getGlobalSiteManager

class EntityAPI(object):

    def __init__(self, instance):
        self.instance = instance

    def pi_ing(self):
        # make "pi_ing"


@implementer(IEntityAProtocol)
@adapter(int)
def get_entity_a_by_id(id):
    return EntityAPI(session().query(EntityA).get(id))

getGlobalSiteManager().registerAdapter(get_entity_a_by_id)

现在一切就绪。当您获得 entity_a 的 id 时,在代码的业务逻辑中的某处,您可以执行以下操作:

from interfaces import IEntityAProtocol

def stuff_which_goes_splat():        
    # ...
    entity_id = got_from_somewhere()
    IEntityProtocol(entity_id).pi_ing()

现在,您拥有了接口、数据库实体和 API 逻辑的完整独立实现。好消息是,您不必仅调整对象的 int ID 之类的原始内容,您可以调整任何内容,只要您可以实现从适配器到数据库实体的直接转换。

警告:当然,相对于执行时间点,getGlobalSiteManager().registerAdapter(get_entity_a_by_id)必须已经调用了。

于 2017-02-22T22:35:18.313 回答