Doctrine2-具有关联实体生成查询的理论-InvalidFieldNameException



是的,标题建议:学说正在寻找一个不存在的字段名称。尽管我不知道如何修复它,但这既是真实又不正确。

完整错误:

文件:d: path to project vendor doctrine doctrine dbal lib lib doctrine dbal dbal driver atrackemmysqldriver.php:71

消息:执行'选择独特的ID_2时发生异常 从(选择p0_.name为name_0,p0_.code as Code_1,p0_.id as ID_2 来自product_statuses p0_(dctrn_result订单p0_.language_id asc,name_0 asc limit 25 偏移0':

sqlstate [42S22]:找不到列:1054未知列 'p0_.language_id'in'order子句'

查询错误是由(从上面的错误中(引起的:

SELECT DISTINCT id_2
FROM (
       SELECT p0_.name AS name_0, p0_.code AS code_1, p0_.id AS id_2
       FROM product_statuses p0_
     ) dctrn_result
ORDER BY p0_.language_id ASC, name_0 ASC
LIMIT 25 OFFSET 0

显然,该查询将无法正常工作。ORDER BY应该在子问题中,否则应用dctrn_result替换p0_,并在子查询中获取language_id列。

在Zend Framework中控制器的索引中,使用QueryBuilder构建查询。所有这些都非常正常,并且在使用addOrderBy()函数的单个ORDER BY语句时,相同的功能非常好。在这种情况下,我希望首先使用2使用2,然后用名称使用。但是以上发生了。

如果有人知道这是一个完整的解决方案(或者是一个错误?(,那很好。否则,将不胜感激地朝着正确的方向来帮助我解决这个问题。

以下其他信息 - 实体和indexAction()

productStatus.php -entity - 注意language_id列的存在

/**
 * @ORMTable(name="product_statuses")
 * @ORMEntity(repositoryClass="HzwProductRepositoryProductStatusRepository")
 */
class ProductStatus extends AbstractEntity
{
    /**
     * @var string
     * @ORMColumn(name="name", type="string", length=255, nullable=false)
     */
    protected $name;
    /**
     * @var string
     * @ORMColumn(name="code", type="string", length=255, nullable=false)
     */
    protected $code;
    /**
     * @var Language
     * @ORMManyToOne(targetEntity="HzwCountryEntityLanguage")
     * @ORMJoinColumn(name="language_id", referencedColumnName="id")
     */
    protected $language;
    /**
     * @var ArrayCollection|Product[]
     * @ORMOneToMany(targetEntity="HzwProductEntityProduct", mappedBy="status")
     */
    protected $products;
    [Getters/Setters]
}

索引 - 删除与QueryBuilder无直接相关的零件。在评论中添加了显示的参数。

    /** @var QueryBuilder $qb */
    $qb = $this->getEntityManager()->createQueryBuilder();
    $qb->select($asParam)              // 'pro'
        ->from($emEntity, $asParam);   // HzwProductEntityProductStatus, 'pro'
    if (count($queryParams) > 0 && !is_null($query)) {
        // [...] creates WHERE statement, unused in this instance
    }
    if (isset($orderBy)) {  
        if (is_array($orderBy)) { 
            // !!! This else is executed !!!   <-----
            if (is_array($orderDirection)) { // 'ASC'
                // [...] other code
            } else {
                // $orderBy = ['language', 'name'], $orderDirection = 'ASC'
                foreach ($orderBy as $orderParam) {
                    $qb->addOrderBy($asParam . '.' . $orderParam, $orderDirection);
                }
            }
        } else {
            // This works fine. A single $orderBy with a single $orderDirection
            $qb->addOrderBy($asParam . '.' . $orderBy, $orderDirection);
        }
    }

============================================================

更新:我发现问题

上面的问题不是由不正确的映射或可能的错误引起的。这是QueryBuilder在创建查询时不会自动处理实体之间的关联。

我的期望是,当一个实体(例如上面的productStatus(包含关系的ID(即language_id列(时,就可以在QueryBuilder中使用这些属性而不会毫无疑问。

请在下面查看我自己的答案,我如何修复我的功能,以便能够对单个嵌套的默认处理(即ProductStatus#语言==语言,能够将language.name用作ORDER BY标识符(。

好的,在更多地搜索并挖掘出错误的方法和何处后,我发现学说在生成查询期间不处理实体的关系类型属性;或者,如果没有指定任何指定,则可能不会默认使用说明实体的主要键。

在上面的问题的用例中, language属性是与Language实体的@ORMManyToOne关联。

我的用例调用能够处理默认操作的租赁一级关系的能力。因此,在我意识到这不是自动处理的(或用language.idlanguage.name作为标识符等修改(后,我决定为其编写一个小功能。

/**
 * Adds order by parameters to QueryBuilder. 
 * 
 * Supports single level nesting of associations. For example:
 * 
 * Entity Product
 * product#name
 * product#language.name
 * 
 * Language being associated entity, but must be ordered by name. 
 * 
 * @param QueryBuilder  $qb
 * @param string        $tableKey - short alias (e.g. 'tab' with 'table AS tab') used for the starting table
 * @param string|array  $orderBy - string for single orderBy, array for multiple
 * @param string|array  $orderDirection - string for single orderDirection (ASC default), array for multiple. Must be same count as $orderBy.
 */
public function createOrderBy(QueryBuilder $qb, $tableKey, $orderBy, $orderDirection = 'ASC')
{
    if (!is_array($orderBy)) {
        $orderBy = [$orderBy];
    }
    if (!is_array($orderDirection)) {
        $orderDirection = [$orderDirection];
    }
    // $orderDirection is an array. We check if it's of equal length with $orderBy, else throw an error.
    if (count($orderBy) !== count($orderDirection)) {
        throw new InvalidArgumentException(
            $this->getTranslator()->translate(
                'If you specify both OrderBy and OrderDirection as arrays, they should be of equal length.'
            )
        );
    }
    $queryKeys = [$tableKey];
    foreach ($orderBy as $key => $orderParam) {
        if (strpos($orderParam, '.')) {
            if (substr_count($orderParam, '.') === 1) {
                list($entity, $property) = explode('.', $orderParam);
                $shortName = strtolower(substr($entity, 0, 3)); // Might not be unique...
                $shortKey = $shortName . '_' . (count($queryKeys) + 1); // Now it's unique, use $shortKey when continuing
                $queryKeys[] = $shortKey;
                $shortName = strtolower(substr($entity, 0, 3));
                $qb->join($tableKey . '.' . $entity, $shortName, Join::WITH);
                $qb->addOrderBy($shortName . '.' . $property, $orderDirection[$key]);
            } else {
                throw new InvalidArgumentException(
                    $this->getTranslator()->translate(
                        'Only single join statements are supported. Please write a custom function for deeper nesting.'
                    )
                );
            }
        } else {
            $qb->addOrderBy($tableKey . '.' . $orderParam, $orderDirection[$key]);
        }
    }
}

它绝不支持QueryBuilder提供的一切,绝对不是最终解决方案。但是它给出了一个抽象功能的起点和可靠的"默认功能"。

最新更新