3

私は最近、パフォーマンスと抽象化の問題のために Doctrine をやめて、データベース主導のロジックに移行しようとしています。私は主にPostgreSQLを使用しています。

教義

Doctrine で気に入った点の 1 つは継承で、これを Web アプリの複数のロールに使用しました。基本テーブル/クラス Person があり、すべてのロール (管理者、開発者、ユーザーなど) がこのクラスを拡張します。すべてのユーザーが 1 つのベース テーブルを共有するため、一意のログイン/識別子 (私の場合は電子メール) を保持するのに役立ちます。しかし、ドクトリンから人の情報を取得すると、そのすべてのプロパティを備えた最終的なクラスが得られました。例えば:

$user = $em->getRepository('Entities\Person')->findOneBy(array('email' => 'john.doe@example.com'));
if ( $user instanceof Entities\Developer) {
    ... 
}

素晴らしい機能ですが、多くのロールがある場合、結果の SQL クエリは非常に効果的ではありませんでした。基本クラスから選択すると、すべてのロールが結合されたままになり、定義された識別子マッパーによって、基本テーブルと最終テーブルから最終クラスが構築されました。

PostgreSQL

postgres がテーブルの継承を実装しており、うまく機能していることを発見しました。しかし、Doctrine の動作をシミュレートして、db から役割を取得したいと思います (それが役割であり、したがって最終テーブルであることがわからない場合)。

より良い例として、私のテーブルは次のようになります。

--
-- base people table
--
CREATE TABLE people
(
  id serial NOT NULL,
  first_name character varying(25) NOT NULL,
  last_name character varying(25) NOT NULL,
  email character varying(50) NOT NULL,
  "password" character varying(150),
  CONSTRAINT people_pkey PRIMARY KEY (id)
);


--
-- role developer (does not have any role specific info)
-- 

CREATE TABLE developer
(
-- Inherited from table people:  id integer NOT NULL DEFAULT nextval('people_id_seq'::regclass),
-- Inherited from table people:  first_name character varying(25) NOT NULL,
-- Inherited from table people:  last_name character varying(25) NOT NULL,
-- Inherited from table people:  email character varying(50) NOT NULL,
-- Inherited from table people:  "password" character varying(150),
  CONSTRAINT developer_pkey PRIMARY KEY (id)
)
INHERITS (people);

--
-- role user
-- 

CREATE TABLE installer
(
-- Inherited from table people:  id integer NOT NULL DEFAULT nextval('people_id_seq'::regclass),
-- Inherited from table people:  first_name character varying(25) NOT NULL,
-- Inherited from table people:  last_name character varying(25) NOT NULL,
-- Inherited from table people:  email character varying(50) NOT NULL,
  client character varying(50),
-- Inherited from table people:  "password" character varying(150),
  CONSTRAINT installer_pkey PRIMARY KEY (id)
)
INHERITS (people);

ソリューション 1 -> 2 つのクエリ

ベース テーブル people からロールを見つけて、ロールのテーブルから直接選択するのは非常に簡単です。

-- returns name of table (and role) 'developer'
SELECT pg.relname 
FROM people p, pg_class pg
WHERE pg.oid=p.tableoid and p.email = 'john.doe@example.com';

-- getting roles full info
SELECT *
FROM developer
WHERE email = 'kracmar@dannax.sk';

この解決策は問題ありませんが、より良い解決策を探していました。

解決策 2 -> プロシージャを使用した 1 つのクエリ

単一のクエリでユーザーに関する情報を取得できれば便利です。関数のドキュメントを深く掘り下げて何かを掘り下げましたが、最後まで到達できませんでした。リターンクエリを使用するのが良いと思いましたが、私の問題は、機能する結果のタイプを指定する必要があることですが、ユーザーの役割 (列とタイプの数が異なるテーブル) によって変わる可能性があります。

これは結果の 1 つです。関数はレコードを返しますが、クエリではなく、すべてのフィールドがカンマで区切られた単一の列です。

    CREATE OR REPLACE FUNCTION get_person_by_email(person_email VARCHAR) 
            RETURNS record 
            LANGUAGE plpgsql 
            STABLE STRICT AS
    $BODY$
            DECLARE 
                    role varchar;
                    result record;

            BEGIN

                    SELECT pg.relname 
                    INTO role
                    FROM people p,
                            pg_class pg
                    WHERE pg.oid=p.tableoid
                            AND p.email = person_email;

                    IF NOT FOUND THEN
                            RAISE exception 'Person with email % does not exists.', person_email;
                    END IF;

                    CASE 
                            WHEN role = 'developer' THEN
                                    SELECT * 
                                    INTO result 
                                    FROM developer
                                    WHERE email = person_email;
                            WHEN ROLE = 'installer' THEN
                                    SELECT * 
                                    INTO result
                                    FROM installer
                                    WHERE email = person_email;

                    END CASE;

                    RETURN result;
            END;
    $BODY$;

列の定義が欠落しているため、この関数から選択することはできません。たぶん私は物事を複雑にして解決策1を使用する必要がありますが、その方法では何も学びません. どんな助けでも大歓迎です。

4

1 に答える 1

1

I suppose you might be interested in zyxist's Doctrine2 fork:

Fork of Doctrine 2 Object Relational Mapper aiming to create real table inheritance support for PostgreSQL

You can read more on author's blog.

于 2011-07-22T15:19:27.253 に答える