2012-07-26 22 views
0

我遇到了以多态方式将记录加载到数据库的问题。Python中的多态性和数据库加载

我:

  • 一个“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更好吗?如果是这样,为什么?

干杯, 威尔

回答

0

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

+0

这将提高一个问题,如果我们要对数据库类的不同实现(我们做的,其实)不​​同的存储过程。我不愿意将特定于数据库的信息放入记录类中。 – wrgrs 2012-07-26 21:13:07

+0

不管你仍然必须编写新的功能,而是在一个类你将它移动到距离和OOP设计抽离的数据库类。 – sean 2012-07-27 13:18:56

+0

@sean这是回应wilbo还是我?对我而言,您希望完整保留数据库类,而不是为每种不同的记录类型添加案例。因此,您将了解哪些存储过程可以与记录类一起使用,但需要实际实现它的数据库类。要么我们你有每个存储过程的DB子类的数量,并有记录用来获得它所需的工厂类。 – 2012-07-27 14:30:52

1

对我来说最有意义的是拥有一个基类,该基类拥有基本的数据库功能,比如将某些东西放入数据库和连接信息中。从这个基类中,你将继承RecordA,RecordB,RecordC,...这将保存诸如存储过程信息之类的信息/功能。在我看来,拥有一大堆方法的基类感觉笨重,并且不适合OOP范例。

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

+0

我不会想到这样做。我打算把数据库类分为不同类型的数据库(Oracle,MySQL)。 – wrgrs 2012-07-31 08:13:14

+0

啊,在这种情况下,我会拿出你的不同组件之间的通用接口,以使其透明的子类,虽然这可能无法正常工作到您的存储过程完全,但如果处理得当将需要更少的代码的开销。 – sean 2012-07-31 12:55:52

0

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

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

它非常灵活,这取决于你想做什么,是否喜欢它的简单的东西:

  • 基类(数据库层)
  • 子类(纯Python电话 - 这样的控制器逻辑运行的相同的表)

  • 基类(抽象层 - 共同控制研究呃逻辑,没有表定义)
  • 子类(数据库层 - 每一个限定不同的数据库表)

  • 基类(数据库层 - 定义根表)
  • 子类(数据库图层 - 定义了继承的表格,对于支持它的Db,或者对那些不支持的表格重复列表)

这里是一个例子E:

# 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个不同类别(水果,苹果,香蕉),和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>]