收到的数据正确时,Doctrine2水合不正确

时间:2016-08-17 09:40:50

标签: php doctrine-orm zend-framework2 hydration

编辑2018-05-22:无答案完全修复问题 - 无法再复制问题,因为无法再访问。不基于this meta discussion

删除

请不要花时间/精力创建答案

在@Wilt的答案中的讨论让我了解了现在使用鉴别器的所有知识,它可能对未来的提问者有所帮助。在我的情况下,它有所帮助,但没有提供答案。

我遇到了一些复杂的问题,从客户端收到的数据水化不正确。我已经尝试将问题解决了近一周,所以我想问你们。

我们已经有了这个应用程序,可以为学生创建作业。作业可能包含问题,文本项目,媒体项目等。问题在于问题和相关的答案。

方案

分配

  • 问题表1(L1)
    • 问题1(L1 - V1)
      • 答案A(L1 - V1 - A1)
      • 答案B(L1 - V1 - A2)
    • 问题2(L1 - V2)
      • 答案A(L1 - V2 - A1)(仅1回答)
  • 问题表2(L2)
    • 问题1(......等等)
      • 答案A
      • 答案B
    • 问题2
      • 答案A
      • 答案B
    • 问题3
      • 答案A
      • 答案B

以上内容从客户端正确发送。剪切该数据的屏幕截图:

Client side data

需要注意的重要一点是,正如您在上面所看到的,Question实际上是GridElements实体。它可能也是TextImage,这是基于属性type = question Discriminator

在对数据进行保湿后,我们得到以下实体结构:

Hydrated data

如您所见,水合后数据不再正确。这是在$form->isValid()期间完成的。 QuestionSheet 1包含Question的第一个QuestionSheet 2,而Question包含第二个Answer的第三个Question中的第一个QuestionSheet

在阅读完整的水合数据集时,我发现为第一个Answers创建的QuestionSheet已被删除。第二个Answers中的QuestionSheet已被复制,并在第一个问题表中覆盖了答案。从本质上讲,您在上图中看到了什么。

更糟糕

以下是上述之后保存到数据库的所有数据,上面提到了2个列表,5个问题和9个答案。

Database data

在第一个问题中,没有Q& A离开。第二个问题表的问题已用于覆盖它们。此外,只有最后2个答案,填补了应该是9的空间!

顺便说一句,返回此内容的查询完全是LEFT JOIN,以便显示所有空数据,这就是剩下的所有内容。

它似乎抓住了最后一组任何子实体来填充以前的实体或其他东西。我迷路了。

这怎么可能?

正如我所提到的,我已经很长时间了,但无法找到解决方案。希望你们能帮忙。

如果您需要有关代码的任何信息,我会尽力在此处显示或在某些专有代码的情况下尽可能地解释它。

更新 - 实体

作业实体

/**
 * @ORM\Entity(repositoryClass="Wms\Admin\Assignment\Repository\AssignmentRepository" )
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name="ass_assignment")
 * @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false)
 */
class Assignment extends SeoUrl
{
    //Traits and properties

    /**
     * @ORM\OneToMany(targetEntity="Wms\Admin\Assignment\Entity\QuestionSheet", mappedBy="assignment", cascade={"persist", "remove"}, orphanRemoval=true)
     **/
    protected $questionSheets;

    public function __construct()
    {
        $this->abstractEntity_entityCategories = new ArrayCollection();
        $this->questionSheets = new ArrayCollection();
        $this->documents = new ArrayCollection();
    }

    public function __toString()
    {
        return (string)$this->id;
    }

    //More getters/setters
}

问题表单实体

/**
 * @ORM\Entity(repositoryClass="Wms\Admin\Assignment\Repository\QuestionSheetRepository")
 * @ORM\Table(name="ass_questionsheet")
 **/
class QuestionSheet extends AbstractEntity
{    
    /**
     * @ORM\ManyToOne(targetEntity="Wms\Admin\Assignment\Entity\Assignment", inversedBy="questionSheets")
     * @ORM\JoinColumn(name="assignment_id", referencedColumnName="id", onDelete="CASCADE")
     **/
    protected $assignment;

    /**
     * @ORM\OneToOne(targetEntity="Wms\Admin\LayoutGrid\Entity\Grid", cascade={"persist", "remove"})
     * @ORM\JoinColumn(name="grid_id", referencedColumnName="id")
     **/
    protected $grid;

    public function __construct()
    {
        $this->gridElements = new ArrayCollection();
    }

    //More getters/setters
}

网格实体

/**
 * @ORM\Entity
 * @ORM\Table(name="lg_grid")
 **/
class Grid extends AbstractEntity
{
    /**
     * @ORM\OneToMany(targetEntity="Wms\Admin\LayoutGrid\Entity\Element\AbstractElement", mappedBy="grid", cascade={"persist", "remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"y" = "ASC", "x" = "ASC"})
     */
    protected $gridElements;

    public function __construct()
    {
        $this->gridElements = new ArrayCollection();
    }
}

网格元素实体

/**
 * @ORM\Table(name="lg_grid_element")
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\HasLifecycleCallbacks
 **/
class AbstractElement extends AbstractEntity implements GridElementInterface
{
    /**
     * @ORM\ManyToOne(targetEntity="Wms\Admin\LayoutGrid\Entity\Grid", inversedBy="gridElements")
     * @ORM\JoinColumn(name="grid_id", referencedColumnName="id", onDelete="CASCADE")
     **/
    protected $grid;

    public $type = ''; //This is a discriminator
}

问题实体

/**
 * @ORM\Entity
 * @ORM\Table(name="lg_grid_question")
 **/
class Question extends AbstractElement
{
    /**
     * @ORM\OneToMany(targetEntity="Wms\Admin\LayoutGrid\Entity\Element\Answer", mappedBy="question", cascade={"persist"})
     */
    protected $answers;

    public $type = 'question'; //Inherited property, now filled in with discriminator value

    public function __construct()
    {
        $this->answers = new ArrayCollection();
    }
}

回答实体

/**
 * @ORM\Entity
 * @ORM\Table(name="lg_grid_answer")
 **/
class Answer extends AbstractEntity
{    
    /**
     * @ORM\ManyToOne(targetEntity="Wms\Admin\LayoutGrid\Entity\Element\Question", inversedBy="answers", cascade={"persist"})
     * @ORM\JoinColumn(name="question_id", referencedColumnName="id", onDelete="CASCADE")
     **/
    protected $question;

    public function __toSting() {
        return (string) $this->getId();
    }
}

更新2 根据@Wilt的回答更新了AbstractElement实体。

/**
 * @ORM\Table(name="lg_grid_element")
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\HasLifecycleCallbacks

 * @ORM\DiscriminatorColumn(name="type", type="string")
 * @ORM\DiscriminatorMap({
 *     "abstractElement"="AbstractElement",
 *     "question"="Question",
 *     //Others
 * })
 **/
class AbstractElement extends AbstractEntity implements GridElementInterface
{
    //Same as above
}

此更新在处理获取正确实体的NonUniformCollection中产生了一些问题。这曾经基于$type属性。

但是,不允许在实体中使用$type属性作为符号* @ORM\DiscriminatorColumn(name="type", type="string")。因此,使用鉴别器的所有类别也已更新如下。

const ELEMENT_TYPE = 'question'; //Overwritten from AbstractElement

/**
 * @return string
 */
public function getType() //Overwritten from AbstractElement
{
    return self::ELEMENT_TYPE;
}
唉,最初的问题仍然存在。

1 个答案:

答案 0 :(得分:0)

我不确定这是否会导致您的问题,但在我看来您的继承映射设置不正确:

您需要在实体定义as written in the docs中声明您的鉴别器列,不应将它们设置为属性,doctrine负责在数据库中设置它们:

searchWord=""; for file in *; do <do stuff 1>;...<do stuff 20>; done;

您的抽象实体是否已正确映射as a @MappedSuperClass

>bash searchWord="end"; <create filelist>; for file in *;...
searchWord=end: No such file or directory

这可能是您解决方案的一部分,请在相应更新后回复反馈......