0

我在以多态方式将记录加载到数据库时遇到问题。

我有:

  • 由不同类型的记录 ( , )Record扩展的 ' ' 对象RecordARecordB
  • 一种load_record()不知道它正在加载什么类型的记录的方法
  • 一个数据库接口,需要包含数据库的所有信息

据我了解,多态我可以这样做:

class RecordA(Record):
    def load_into_db(self, db_impl):
        db_impl.load_record_a(self)


class DbImpl(DbInt):
    def load_record_a(self, record):
        ... 
    def load_record_b(self, record):
        ... 

def load_record(record):
    record.load_into_db(db_impl)

或者

class RecordA(Record):
    def get_record_data(self):
        ....
    def get_db_proc(self, db_impl):
        return db_impl.get_record_a_proc()


class DbImpl(DbInt):
    def get_record_a_proc(self):
        ...

def load_record(record):
    record_data = record.get_data()
    db_proc = record.get_db_proc(db_impl)
    db_impl.load_record(record_data, db_proc)

这两个似乎有点笨拙。或者,我们可以有效地使用 switch 语句:

class DbImpl(DbInt):
    procs = { RecordA: ..., RecordB: ...}
    ...

def load_record(record):
    data = record.get_data()
    db_proc = procs[type(record)]
    db_impl.load_record(record_data, db_proc)

现在可能很明显,问题是数据库需要使用一个特定的存储过程(它在它自己的代码中),但是如果不询问记录本身,它就不知道要使用哪个存储过程。

示例 1 对我来说看起来是最多态的,但是DbImpl每当我们添加新类型的记录时它仍然需要编辑代码,那么它是否比示例 3 更好?如果是这样,为什么?

干杯,威尔

4

3 回答 3

1

对我来说最有意义的是拥有一个包含基本数据库功能的基类,例如将某些内容放入数据库和连接信息。然后,您将从这个基类中继承 RecordA、RecordB、RecordC 等,它们将保存信息/功能,例如存储过程信息。在我看来,拥有一个包含一堆方法的基类感觉很笨拙,并且不适合 OOP 范式。

因此,具有基本数据库功能的基类,然后每个 Record 子类将包含该特定记录类型所需的信息。

于 2012-07-27T13:17:36.307 回答
0

在这种情况下,如果 Record 类型与特定的存储过程相关,那么我会说记录本身需要了解需要运行的存储过程并将该数据传递给实现它的 DB 类。因此,不需要使用每种新记录类型来修改 DB 类。只需要对 recordType 进行编码以了解需要使用的存储过程名称并将该名称公开给 DB 类。

于 2012-07-26T17:31:21.490 回答
0

我遇到了同样的问题,发现现有的数据库 ORM 就多态性/OOP 而言缺乏,为此我一直在研究一个主要关注这一点的新数据库。它称为 ORB,可在以下位置找到:http ://docs.projexsoftware.com/api/orb/

现在它只适用于 PostgreSQL 和 Mongo,但我很快就会将它扩展到更多后端。

它非常灵活,具体取决于您要执行的操作,无论是否简单,例如:

  • 基类(数据库层)
  • 子类(纯 python 调用 - 所以控制器逻辑运行同一个表)

或者

  • 基类(抽象层 - 通用控制器逻辑,未定义表)
  • 子类(数据库层 - 每个定义不同的数据库表)

或者

  • 基类(数据库层 - 定义根表)
  • 子类(数据库层 - 为支持它的 Db 定义继承的表,或为不支持它的 Db 定义重复的列式表)

这是一个例子:

# import the orb system
from orb import Table, Column, ColumnType, Orb

# define the base class (will create default_fruit table)
class Fruit(Table):
    __db_columns__ = [
        Column(ColumnType.String, 'shape'),
        Column(ColumnType.String, 'color'),
        Column(ColumnType.String, 'name'),
        Column(ColumnType.String, 'classType')
    ]

    def initRecord( self ):
        """
        Set the initialization information from the base Table type
        """
        super(Fruit, self).initRecord()
        self.setRecordDefault('classType', self.__class__.__name__)

    @staticmethod
    def expanded( records ):
        """
        Expands the records based on their class type.

        :return   [<Table>, ..]
        """
        out = []
        for record in records:
            # map the record to their base classes
            model = Orb.instance().model(record.classType())
            if ( not model ):
                out.append(record)
                continue

            expanded_record = model(record)
            if ( not expanded_record.isRecord() ):
                continue

            out.append(expanded_record)
        return out        

# define the sub class (no database table)
class Apple(Fruit):
    def initRecord( self ):
        super(Apple, self).initRecord()
        self.setRecordDefault('shape', 'round')
        self.setRecordDefault('color', 'red')

# define the sub class (with a sub-table, will create default_banana table)
class Banana(Fruit):
    __db_columns__ = [
        Column(ColumnType.String, 'isPlantain')
    ]

    def initRecord( self ):
        super(Banana, self).initRecord()
        self.setRecordDefault('shape', 'oblong')
        self.setRecordDefault('color', 'yellow')

这将定义 3 个不同的类(Fruit、Apple、Banana)和 2 个数据库表(default_fruit、default_banana)

使用这个系统(你必须创建文档中定义的数据库连接等)会给你类似的东西:

>>> from fruits import Fruit, Apple, Banana
>>> apple = Apple()
>>> apple.setColor('green')
>>> apple.setName('Granny Smith')
>>> apple.commit()
>>> banana = Banana()
>>> banana.setName('Chiquita')
>>> banana.setPlantain(False)
>>> banana.commit()
>>> fruits = Fruit.select() # select all fruit
[<Fruit>, <Fruit>]
>>> fruits = Fruit.expanded(fruits) # expand the fruit based on their types
[<Apple>, <Banana>]
于 2012-08-01T06:42:52.883 回答