由于性能和抽象问题,我最近试图放弃 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,但那样我什么都学不到。任何帮助将不胜感激。