【发布时间】:2015-11-03 14:26:06
【问题描述】:
Photo 和 Tag 这两个学说 2 实体通过多对多关系链接,并进行相应映射。
每个标签都有一个键和一个值,因此示例键是“照片类型”,示例值是“人”。
我创建了一个自定义存储库 PhotoRepository.php,以方便搜索带有标签对数组(或逗号分隔列表*)的照片,摘录如下:
public function getQueryByTags($tags = null, $limit =0, $start =-1, $boolean ="and")
{
...
$qb->select('p')
->from('MyBundle\Entity\Photo', 'p')
->join('p.tags','t');
# ->join('a.tags','t')
if ($boolean == "and") { $qb->where('1 = 1'); }
$i = 1;
foreach ($tags as $tag) {
if ($boolean == "and") {
$qb->andWhere('t.key = ?'.$i.' AND t.value = ?'.($i+1));
} elseif ($boolean == "or") {
$qb->orWhere('t.key = ?'.$i.' AND t.value = ?'.($i+1));
}
$qb->setParameter($i, $tag['key'])->setParameter(($i+1), $tag['value']);
$i += 2;
}
...
return $qb->getQuery();
}
这适用于单个标签。但是,一旦标签有多个(例如搜索 'photo-type'=>'people', 'person'=>'Bob'),布尔逻辑就会崩溃,不会返回任何结果。
我怀疑这与将连接 Tag 实体中的 andWhere/(orWhere) 子句与 Doctrine2 queryBuilder() 放在一起有关。 (因为同一个标签不能同时是 'photo-type'=>'people' AND 'person'=>'Bob',尽管应该是同一张照片)。
$photos = $em->getRepository('MyBundle:Photo')->
findByTags(array(
array('key' => 'context','value' => $context),
array('key' => 'photo-type','value' => 'field'),
));
我尝试构造一个 JOIN WITH 查询,但这似乎需要一个非常复杂的构造来创建表达式,我无法弄清楚:-
public function getQueryByTags($tags = null, $limit =0, $start =-1, $boolean ="and")
{
...
$qb->select('p')
->from('MyBundle\Entity\Photo', 'p');
$i = 1;
$expr = $qb->expr();
foreach ($tags as $tag) {
if ($boolean == "and") {
$expr = $expr->andX($qb->expr()->eq('t.key', '?'.$i),$qb->expr()->eq('t.value', '?'.($i+1)));
} elseif ($boolean == "or") {
}
$qb->setParameter($i, $tag['key'])->setParameter(($i+1), $tag['value']);
$i += 2;
}
$qb->join('p.tags','t',Doctrine\ORM\Query\Expr\Join::WITH,$expr);
# ->join('a.tags','t')
...
return $qb->getQuery();
}
编辑:最终我想要的结果集是:
“和”搜索:
SELECT all Photos which have (Tag with key(A) AND value(B) ) AND (another Tag with key(C) AND value(D))“或”搜索:
SELECT all Photos which have (Tag with key(A) AND value(B) ) OR (another Tag with key(C) AND value(D))其中:A、B 是第一个唯一标签“对”(例如“照片类型”=“人”或“照片类型”=“动物”),C、D 是另一个唯一标签'pair'(例如,'person'='Bob'、'person'='Tiddles' 或者,理论上 'animal'='Tiddles')
谁能帮我弄清楚如何构造这个复杂的 JOIN WITH 表达式?
或者,如果我好像找错了树,谁能提出一种更优雅的替代方法?
*NB:如果 $tags 是以逗号分隔的字符串形式接收的(例如 $tags="photo-type=people,person=Bob"),它首先被转换成一个数组。
EDIT#2:标签实体,应@Wilt 的要求:
标签.yml
MyBundle\Entity\Tag:
type: entity
table: tag
fields:
id:
id: true
type: integer
unsigned: true
nullable: false
generator:
strategy: IDENTITY
key:
type: string
length: 20
fixed: false
nullable: true
value:
type: string
length: 50
fixed: false
nullable: true
manyToMany:
photos:
targetEntity: Tag
mappedBy: tags
lifecycleCallbacks: { }
Photo.yml(仅提取)
MyBundle\Entity\Photo:
type: entity
repositoryClass: MyBundle\Entity\PhotoRepository
table: photo
fields:
sha1:
....
manyToMany:
tags:
targetEntity: Tag
inversedBy: photos
joinTable:
name: x_photo_tag
joinColumns:
photo_sha1:
referencedColumnName: sha1
inverseJoinColumns:
tag_id:
referencedColumnName: id
【问题讨论】:
-
解释两部分标签的逻辑: ——理论上这个标签对可以建模为一个唯一的字符串(而不是一个唯一的
Tag: key, value;一个唯一的Tag: 'key=value')但是数据源(Web 应用程序外部)的性质使得分别存储键和值更容易进行排序。 (即,可以对键或值字段进行排序)。 –– 它还允许应用程序识别其他对象以将标签值链接回(例如,'person'、'Bob' 或 'person'、'Jill' 到某个索引的 'Person' 对象)。 -
可以在一张图片上添加标签
'photo-type'='people'和'animal'='Tiddles'吗?否则,我建议更改您的模型,让人物图片带有人物标签,动物图片带有动物标签。这将使这一切变得容易得多。 -
是的,
'photo-type'='people'和'animal'='Tiddles'应该是可能的,因为标签是人工创建的,而不是 db 模型在语义上预先确定的。 (这些标签对只是示例)。
标签: symfony join doctrine-orm many-to-many multiple-conditions