3

由于性能和抽象问题,我最近试图放弃 Doctrine,并转向数据库驱动的逻辑。我主要使用 PostgreSQL。

教义

我喜欢 Doctrine 的一件事是继承,我将其用于 Web 应用程序中的多个角色。有基表/类 Person 并且每个角色(例如管理员、开发人员、用户)都扩展了这个类。所有用户共享一个基表,因此有助于保持唯一的登录名/标识符(在我的情况下是电子邮件)。但是从教义中获取人的信息导致了最终类,具有它的所有属性。例如:

$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 个查询

从基表人员中找出角色然后直接从角色表中选择非常简单:

-- 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 使用过程的查询

在单个查询中获取有关用户的信息会很好。我深入研究了函数文档并挖掘了一些东西,但无法完成。我认为使用返回查询会是一种方式,但我的问题是我需要指定要运行的结果类型,但它可以根据用户的角色(具有列数和类型的不同表)而改变。

这是结果之一,函数返回记录但它不是查询,其中所有字段用逗号分隔的单列。

    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

我想你可能对zyxist 的 Doctrine2 fork感兴趣:

Doctrine 2 Object Relational Mapper 的分支旨在为 PostgreSQL 创建真正的表继承支持

您可以在作者的博客上阅读更多内容。

于 2011-07-22T15:19:27.253 回答