У меня есть небольшая сложная проблема, когда гидратация данных, полученных с клиентской стороны, неправильно увлажняется. Я пытался решить проблему почти неделю, поэтому я решил попросить вас, ребята.Неправильная гидратация Doctrine2, когда получены правильные данные
У нас есть это приложение, которое позволяет создавать задания для студентов. Задания могут содержать вопросы, элементы текста, элементы мультимедиа и т. Д. Проблема связана с Вопросами и связанными с ними ответами.
Сценарий
Назначение
- QuestionSheet 1 (L1)
-
- Вопрос 1 (L1 - V1)
-
-
- ответа А (L1 - V1 - А1)
-
-
-
- ответа В (L1 - V1 - А2)
-
-
- Вопрос 2 (L1 - V2)
-
-
- Ответ A (L1 - V2 - A1) (только 1 ответ)
-
- QuestionSheet 2 (L2)
-
- Вопрос 1 (...и так далее)
-
-
- Ответ на
-
-
-
- ответа Б
-
-
- Вопрос 2
-
-
- Ответ на
-
-
-
- ответа Б
-
-
- Вопрос 3
-
-
- Ответ на
-
-
-
- Ответ B
-
выше получает отправить правильно с клиентской стороны. Скриншот отрезала эти данные:
Важно отметить, что, как вы можете видеть выше, Question
фактически является GridElements
сущности. Возможно, это также было Text
или Image
, что основывается на собственности type = question
, которая является Discriminator
. не
После увлажняющих данных мы получаем следующую структуру Entity:
Как вы можете видеть, что данные уже не исправят после гидратации. Это делается во время $form->isValid()
.QuestionSheet 1
содержит первые Question
для QuestionSheet 2
и что Question
имеет первые Answer
с третьего Question
второго QuestionSheet
.
При чтении полного гидратированного набора данных я вижу, что Answers
, созданный для первого QuestionSheet
, был сброшен. Answers
со второго QuestionSheet
были дублированы и перезаписали ответы в первом вопросе. В сущности, то, что вы видите на картинке выше.
еще хуже
Ниже все данные, которые сохраняются в базе данных после того, как выше, с указанным сценарием 2 списков, 5 вопросов и 9 ответов.
Итак первый вопрос, не Q & Левый. Для их перезаписи использовались другие вопросы QuestionSheet. Кроме того, существуют только последние 2 ответа, заполняя пространство того, что должно было быть 9 !.
Btw, запрос, возвращающий это, полностью 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
}
QuestionSheet объект
/**
* @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();
}
}
Update 2 Обновленный 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
который обрабатывает получать правильное Entity. Это было основано на свойстве $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;
}
Увы, исходная проблема остается.
ли вы [проверить вашу схему] (http://docs.doctrine-project.org/ projects/doctrine-orm/en/latest/reference/tools.html # runtime-vs-development-mapping-validation) с доктриной? Может быть, вам следует поделиться определениями своих сущностей? – Wilt
Да, схема подтверждена как ОК, схема БД также хороша. Я немного обновлю вопрос, чтобы добавить столько отношений, сколько необходимо. – Nukeface
Извините, ошибка вызвала уродливую голову в другом месте, конец дня для меня. Обновление до вопроса будет здесь завтра утром (UTC + 1). Я добавлю объекты, необходимые для логики выше и, возможно, что необходимо из форм/полей. Подцепите себя, может быть немало. ;) – Nukeface