首先,我想为这个问题的长度道歉;没有很多背景,我不知道如何正确地提出我的问题。请耐心等待。
我正在转换一个简单的应用程序,用于将我的技能从我自己的自定义数据库访问模式转换为Doctrine。我选择Doctrine有很多原因,其中最重要的原因是我经常在我的日常工作中使用它。我也喜欢Doctrine通常是一个非常薄(出现)的图层,它仍然可以保留不变的功能。
我已将数据库中users
表的数据访问层转换为Doctrine。
除了一些细节之外,它是非常不起眼的(简单的吸气剂和制定者):
User
对象在构造函数ArrayCollection
namespace model\entities;
/**
* @Entity(repositoryClass="model\repositories\UserRepository")
* @Table(name="users")
*/
class User{
/* snip variables */
/**
* @OneToOne(targetEntity="Authentication", mappedBy="user", cascade="persist")
*/
private $authentication;
/**
* @OneToMany(targetEntity="Contact", mappedBy="user", cascade="persist")
*/
private $contacts;
public function __construct() {
$this->contacts = new \Doctrine\Common\Collections\ArrayCollection();
}
/* snip getters and setters */
}
在我的旧架构中,我有两个自定义查询,它们选择了users
表的一个子集。
他们是:
public function search( $term = null ){
if( !$term ){
$sql = "SELECT *
FROM
" . $this->tableName . "
ORDER BY
lname ASC,
fname ASC";
$res = $this->db->q($sql);
}
else{
$sql = "SELECT *
FROM
" . $this->tableName . "
WHERE
lname LIKE ?
OR fname LIKE ?
OR CONCAT(fname, ' ', lname) LIKE ?
ORDER BY
lname ASC,
fname ASC";
$values = array( '%' . $term . '%', '%' . $term . '%', '%' . $term . '%' );
$res = $this->db->qwv( $sql, $values );
}
return $this->wrap( $res );
}
和
public function getAllWithRestrictions(){
$sql = "SELECT *
FROM
" . $this->tableName . "
WHERE
userid IN
(
SELECT
userid
FROM
" . $this->uiPre . "authentications
WHERE
resetPassword = 1
OR disabled = 1
)";
$res = $this->db->q( $sql );
return $this->wrap($res);
}
其中$this->db
为精简PHP PDO wrapper和$this->wrap
does magic,返回零/单/多行并将其转换为data objects。
现在,我认为这很容易转换为Doctrine。在getAllWithRestrictions
的情况下,它只是一个->where
,->orWhere
集,对吧?我不知道了。
我发现这些Stackoverflow问题曾经尝试构建我的查询,但是我在错误之后遇到错误,而且我不确定兔子洞需要走多远:
SQL Multiple sorting and grouping
Order by multiple columns with Doctrine
Doctrine: Multiple (whereIn OR whereIn) query?
Doctrine - or where?
我的自定义存储库目前看起来像这样,但我不能说它甚至接近正确,因为我一直在摆弄它很长一段时间,它只是我认为可能有用的一个大杂烩:< / p>
<?php
namespace model\repositories;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr;
class UserRepository extends EntityRepository{
public function search( $term ){
if( !$term ){
return $this
->_em
->createQuery('SELECT u FROM model\entities\User u')
->addOrderBy( 'u.lname' )
->addOrderBy( 'u.fname' )
->getResult();
}
else{
$qb = $this->_em->createQueryBuilder();
$qb ->select(array('u'))
->from('model\entities\User', 'u')
->where( $qb->expr()->like( 'u.lname', '?1' ) )
->orWhere( $qb->expr()->like( 'u.fname', '?2' ) )
->orWhere( $qb->expr()->like( 'CONCAT(u.fname, \' \', u.lname)', '?3' ) )
->addOrderBy( 'u.lname' )
->addOrderBy( 'u.fname' )
->setParameters(
array(
1 => $term,
2 => $term,
3 => $term
)
);
$query = $qb->getQuery();
return $query->getResult();
}
}
public function getAllWithRestrictions(){
$qb = $this->_em->createQueryBuilder();
$qb ->select(array('u'))
->from('model\entities\User', 'u')
->add('where', $qb->expr()->orx(
$qb->expr()->eq('u.disabled', '1'),
$qb->expr()->eq('u.resetPassword', '1')
));
$query = $qb->getQuery();
return $query->getResult();
}
}
编辑:我刚刚意识到我在错误的表上进行getAllWithRestrictions
查询(它应该是authentications
。)无论如何,这是导致我的问题正确的搜索方法现在。但是,我还需要知道如何做$qb->expr()->eq('u.Authentication.disabled = '1')
这样的事情,我不知道DQL是如何工作的。
我现在遇到的特殊错误是
Fatal error: Uncaught exception 'Doctrine\ORM\Query\QueryException' with message 'SELECT u FROM model\entities\User u WHERE u.lname LIKE ?1 OR u.fname LIKE ?2 OR CONCAT(u.fname, ' ', u.lname) LIKE ?3 ORDER BY u.lname ASC, u.fname ASC'
接着是
Doctrine\ORM\Query\QueryException: [Syntax Error] line 0, col 99: Error: Expected Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS, got ','
但是我有很多不同的问题,这取决于我如何构建DQL / Query Builder。
同样,我希望这两个SQL查询很容易转换为Doctrine / DQL。我想这样做而不需要通过Doctrine的原始SQL(我链接的许多已接受的答案建议)。这一定很容易。 有谁知道如何构建优雅的Doctrine查询?
答案 0 :(得分:1)
根据教义中的CONCAT
函数解析器,它只需要用逗号分隔的2个参数,
//Doctrine/ORM/Query/AST/Functions/ConcatFunction.php
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->firstStringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->secondStringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
所以这个
->orWhere( $qb->expr()->like( 'CONCAT(u.fname, \' \', u.lname)', '?3' ) )
应该是
->orWhere( $qb->expr()->like( 'CONCAT(u.fname, u.lname)', '?3' ) )
这不会引发任何错误,但可能不是你真正需要的。在这种情况下,您必须为CONCAT
推送自己的自定义函数:)
答案 1 :(得分:1)
除了@ Broncha上面的回答(通过添加嵌套CONCAT
如'CONCAT(u.fname, CONCAT(\' \', u.lname))'
帮助解决错误),可以通过加入所需的实体来修复另一个函数,然后添加{{ 1}}关于连接的子句如下:
WHERE