2016-08-17 5 views
1

У меня есть небольшая сложная проблема, когда гидратация данных, полученных с клиентской стороны, неправильно увлажняется. Я пытался решить проблему почти неделю, поэтому я решил попросить вас, ребята.Неправильная гидратация 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

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

Client side data

Важно отметить, что, как вы можете видеть выше, Question фактически является GridElements сущности. Возможно, это также было Text или Image, что основывается на собственности type = question, которая является Discriminator. не

После увлажняющих данных мы получаем следующую структуру Entity:

Hydrated data

Как вы можете видеть, что данные уже не исправят после гидратации. Это делается во время $form->isValid().QuestionSheet 1 содержит первые Question для QuestionSheet 2 и что Question имеет первые Answer с третьего Question второго QuestionSheet.

При чтении полного гидратированного набора данных я вижу, что Answers, созданный для первого QuestionSheet, был сброшен. Answers со второго QuestionSheet были дублированы и перезаписали ответы в первом вопросе. В сущности, то, что вы видите на картинке выше.

еще хуже

Ниже все данные, которые сохраняются в базе данных после того, как выше, с указанным сценарием 2 списков, 5 вопросов и 9 ответов.

Database data

Итак первый вопрос, не 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; 
} 

Увы, исходная проблема остается.

+0

ли вы [проверить вашу схему] (http://docs.doctrine-project.org/ projects/doctrine-orm/en/latest/reference/tools.html # runtime-vs-development-mapping-validation) с доктриной? Может быть, вам следует поделиться определениями своих сущностей? – Wilt

+0

Да, схема подтверждена как ОК, схема БД также хороша. Я немного обновлю вопрос, чтобы добавить столько отношений, сколько необходимо. – Nukeface

+0

Извините, ошибка вызвала уродливую голову в другом месте, конец дня для меня. Обновление до вопроса будет здесь завтра утром (UTC + 1). Я добавлю объекты, необходимые для логики выше и, возможно, что необходимо из форм/полей. Подцепите себя, может быть немало. ;) – Nukeface

ответ

0

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

Вы должны объявить столбец дискриминатора внутри вашей организации определений as written in the docs, они не должны быть установить в качестве свойств, доктрина заботится о настройке их в базе данных:

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

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

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

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

+0

Привет, Уилт, я добавил дополнительную информацию в вопрос, основываясь на вашем ответе (см. Обновление 2). Однако проблема остается. Есть ли шанс увидеть другой? – Nukeface

+0

@Nukeface Вы также указали свой 'AbstactEntity' как' @ MappedSuperclass'? – Wilt

+0

К сожалению, я забыл ответить, что да, это абстрактный класс с отображением MappedSuperClass: '/ * * @ORM \ MappedSuperclass * @ORM \ HasLifecycleCallbacks */ абстрактный класс AbstractEntity реализует AbstractEntityInterface {// вещи}' – Nukeface