Неправильная гидратация Doctrine2, когда полученные данные верны

РЕДАКТИРОВАТЬ 2018-05-22: нет ответа полностью исправлена ​​проблема — больше не может копировать проблему, поскольку больше не имеют доступа. Не удаляется на основе это мета обсуждение

Пожалуйста, не тратьте время / усилия на создание ответа

Обсуждение в ответе @ 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 (… и так далее)
      • Ответ А
      • Ответ Б
    • вопрос 2
      • Ответ А
      • Ответ Б
    • Вопрос 3
      • Ответ А
      • Ответ Б

Вышеуказанное правильно отправляется со стороны клиента. Снимок экрана с этими данными:

Данные на стороне клиента

Важно отметить, что, как вы можете видеть выше, 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&А слева. Вопросы второго вопросника были использованы для их перезаписи. Кроме того, есть только последние 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
обновленный AbstractElement сущность, основанная на ответе @ Wilt.

/**
* @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

Решение

Я не уверен, является ли это причиной вашей проблемы, но мне кажется, что ваше наследование не правильно настроено:

Вы должны объявить свой столбец дискриминатора в определениях вашей сущности как написано в документах, они не должны быть установлены как свойства, доктрина заботится об их установке в вашей базе данных:

/**
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="type", type="string")
* @DiscriminatorMap({"element"="AbstractElement", "question"="Question", "text"="TextItem", "media"="MediaItem"})
*/
class AbstractElement extends AbstractEntity implements GridElementInterface
{
//...
}

И правильно ли сопоставлена ​​ваша абстрактная сущность? как @MappedSuperClass?

/**
* @MappedSuperclass
*/
class AbstractEntity
{
//...
}

Это может быть частью вашего решения, пожалуйста, вернитесь с обратной связью после того, как вы обновили соответственно …

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]