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 パラダイムに適合しません。

したがって、基本的なデータベース機能を備えた基本クラスであり、各レコード サブクラスには、その特定のレコード タイプに必要な情報が含まれます。

于 2012-07-27T13:17:36.307 に答える
0

私は同じ問題に遭遇し、ポリモーフィズム/OOP に関する限り、既存のデータベース ORM が欠けていることを発見しました。そのために、主にそれに焦点を当てた新しいものに取り組んでいます。これは ORB と呼ばれ、http: //docs.projexsoftware.com/api/orb/で見つけることができます。

現在は PostgreSQL と Mongo でのみ動作しますが、すぐにより多くのバックエンドに拡張する予定です。

次のような単純なものであるかどうかにかかわらず、何をしようとしているかに応じて非常に柔軟です。

  • 基本クラス (データベース層)
  • サブクラス (純粋な python 呼び出し - 同じテーブルを実行するコントローラー ロジック)

また

  • 基本クラス (抽象レイヤー - 共通のコントローラー ロジック、テーブルは定義されていません)
  • サブクラス (データベース層 - それぞれが異なるデータベース テーブルを定義)

また

  • 基本クラス (データベース層 - ルート テーブルを定義)
  • サブクラス (データベース層 - 継承されたテーブルを定義し、それをサポートする 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 に答える
0

この場合、レコード型が特定のストアド プロシージャに関連している場合、レコード自体が実行する必要があるストアド プロシージャを理解し、そのデータを実装先の DB クラスに渡す必要があると言えます。したがって、新しいレコード タイプごとに DB クラスを変更する必要はありません。recordType をコーディングして、使用する必要があるストアド プロシージャ名を理解し、その名前を DB クラスに公開するだけで済みます。

于 2012-07-26T17:31:21.490 に答える