Doctrine 2查找具有属性的页面

时间:2014-07-24 14:04:59

标签: php mysql sql doctrine-orm dql

我需要使用页面属性的过滤条件填充查询构建器。我得到了Enities" Page","属性"和"价值"

Page: id, name, etc
Attribute: id, name, etc
Value: page_id, date, string, numeric

我需要获取在表单中选择属性值的所有页面。

所以我得到了Query Builder:

$qb->select('p')
   ->from(Page p)
   ->leftJoin(p.values);

我可以使用"有"或"其中"条款要做什么?

$qb->add('having', 'a.id = :attr1_id AND a.value = :attr1_val')
$qb->add('having', 'a.id = :attr2_id AND a.value = :attr2_val')

更新:不,我不能。通过这种方式,它可以获取attr1_id = attr2_value和attr2_id = attr1_value的页面,并且所有条件都为真,但结果是错误的。

或者我应该为每个值添加自定义连接?

更新:这里有工作原理:

//attr1.intval=:a1 (or LIKE, BETWEEN, etc compare)
$comp_expression=$aliace.'.'.$value_field.'=:a'.$this->getId();
//INNER JOIN attribute attr1 ON attr1.type=5 AND attr1.intval=:a1
$qb->innerJoin($value_class, $aliace , 'WITH', $aliace.'.type='.$this->getId().' AND '.$comp_expression);
//where attr1.intval IS NOT NULL
$qb->andWhere($aliace.'.'.$value_field.' IS NOT NULL');
$qb->setParameter('a'.$this->getId(),$value);

更新:那么执行键+值filtring的唯一方法是为每个过滤条件添加连接?我现在有27个属性,所以需要用27个连接构建查询吗?

还有另一种方式可以做到这一点吗?很抱歉,如果这是重复的,则无法找到找到相同问题的关键字。

更新:也许我shuld退出sql查询限制并为它创建mysql程序?

更新:我可以在学说中使用这样的东西吗? MySQL optimization on filtering key-value pairs as records

2 个答案:

答案 0 :(得分:1)

两种方法之间没有这种区别,这两种方法完全相同。

从问题的中心点来看,我怀疑是使用类似的构造查询。

您提供的第一个示例是workfull。 你提出的第二个例子是不对的。

在第二个示例中,您需要在andWhere方法上定义所有where子句。

$qb->innerJoin('a1 ON p.id=a1.page_id');
$qb->andWhere('a1.attribute_id=:attr1_id ');
$qb->andWhere('a1.value=:attr1_val');
$qb->andWhere('a1 is not null');

你所做的就是通过第三个api创建一个sql,Doctrine ORM是php最成功的orm工具之一,知道如何使用它将让你体验ORM的力量,通过学说实现你需要的所有东西知道在那里:

Doctrine Create Query Builder - >你也一样。

Doctrine Query Builder

Doctrine创建查询 - >最简单的形式

Query Language

答案 1 :(得分:1)

模型

您在此处使用的模型称为Entity-Attribute-Value(EAV)。如果您不知道我建议您首先阅读专业人士和骗子。

其中一个问题是在EAV模型中搜索很困难且效率很低。

AND查询

您似乎想要查询具有特定属性的特定值的实体和特定属性的另一个特定值。这些类型的查询在EAV模型中非常有效。

我们假设您的实体设置为:

Entity:    id, attributes (one-to-many), values (one-to-many)
Attribute: id, name, entity (many-to-one), values (one-to-many)
Value:     id, content, entity (many-to-one), attribute (many-to-one)

假设您要查询具有值为color的属性blue的所有实体。 Doctrine查询看起来像这样:

SELECT e FROM Entity e
JOIN e.values v JOIN v.attribute a
WHERE a.name = 'color' AND v.content = 'blue'

(当然你不应该像这样在DQL中使用值,而是将它们绑定为参数。)

现在让我们假设您要查询属性color的所有实体,其值blue 属性shape,其值为{{ 1}}。查询变为:

square

现在,如果要查询3个属性/值对,则需要其中3个JOIN集。如果要查询4个属性/值对,则需要4个JOIN集。等

OR查询

假设您要查询属性SELECT e FROM Entity e JOIN e.values v1 JOIN v.attribute a1 JOIN e.values v2 JOIN v.attribute a2 WHERE a1.name = 'color' AND v1.content = 'blue' AND a2.name = 'shape' AND v2.content = 'square' 的所有实体,其值为color 属性blue,其值为{{1 }}。查询变为:

shape

您可以看到这更有效,您不需要为每个额外的属性/值对提供额外的JOIN集。

混合AND OR

我将在这里做空:这将成为查询的噩梦。我强烈建议你这样做。

替代

如果您的应用程序将严重依赖这些类型的查询(特别是AND和混合AND OR),我建议您考虑使用不同类型的存储引擎。关系数据库并不适合这种事情。

您可能更善于使用Document Oriented Database,例如ElasticsearchMongoDBCouchDB等。

混合替代

您还可以将EAV部件“复制”到面向文档的数据库,并仅将其用于搜索功能。我建议您为实体(创建,更新,删除)进行更改时设置事件。然后创建将这些更改保留在Document存储中的侦听器。

这样,您的应用程序可以使用Relational Database进行正常操作,使用Document store进行搜索。在这种情况下,我建议Elasticsearch,这非常适合这种事情。