Как я могу предотвратить сохранение нежелательной доктрины в Symfony 4? - PullRequest
1 голос
/ 24 апреля 2019

На данный момент я не уверен, что проблема в доктрине или в symfony.

У меня есть сущность, которая называется Field.Он имеет свойство dataTable с обычными методами получения и установки.В одном из моих вспомогательных классов я использую метод setter, чтобы изменить dataTable на временное значение.Я никогда не называю persist в этом классе или контроллере, который его вызывает.Однако я обнаружил, что база данных обновляется с помощью этого временного значения.

Если необходимо, я могу добавить виртуальное свойство и использовать его вместо этого, но я думаю, что код будет чище, если я смогу избежатьтот.Как я могу гарантировать, что доктрина сохраняет только то, о чем я прямо говорю?

Сопоставление сущностей:

type: entity

gedmo:
  soft_deleteable:
    field_name: deletedAt
    time_aware: false

id:
  id:
    type: integer
    generator:
      strategy: auto

fields:
  name:
    type: string
  sortorder:
    type: integer
  dataTable:
    type: string
  type:
    type: string
  columnAdded:
    type: boolean
  deletedAt:
    type: date
    nullable: true

manyToOne:
  section:
    targetEntity: Domain\Model\Section
    inversedBy: fields

oneToMany:
  fieldOptions:
    targetEntity: FieldOption
    mappedBy: field

oneToOne:
  zmrList:
    targetEntity: Domain\Model\ZmrList

Соответствующий код контроллера: (Persist никогда не вызывается для чего-либо в контроллере)

 $columns = $this->queryBuilder->getListColumns($list);
 $filters = $this->queryBuilder->composeListFilters($list);
 $query = $this->queryBuilder->build($columns, $filters, $list->getForm()->getId(), $instanceId);

Соответствующий код в QueryBuilder:

 foreach ($details['columns'] as $k=>$layerColumn) {
                        $this->columns[$layerColumn]->getField()->setDataTable('table_'.$alias);
}

Функция Setter:

 /**
     * @param string $dataTable
     */
    public function setDataTable(string $dataTable): void
    {
        $this->dataTable = $dataTable;
    }

Ответы [ 2 ]

1 голос
/ 29 апреля 2019

Вы можете сделать это, изменив Change Tracking Policy с Deferred Implicit (по умолчанию) на Deferred Explicit. Если изменить его на явное, в базу данных будут сохранены только те объекты, которые вы пометили persist(), даже обновления (в схеме implicit все обновления отслеживаются). У него есть еще один плюс в том, что он намного более дружественен к памяти, поскольку ему не нужно проходить через каждый объект, который находится в хранилище доктрины, он проходит только через те, которые вы отметили для сохранения с помощью persist().

Вот как это сделать через yaml:

type: entity
changeTrackingPolicy: DEFERRED_EXPLICIT # can be DEFERRED_IMPLICIT, DEFERRED_EXPLICIT or NOTIFY

# the rest of your config
1 голос
/ 24 апреля 2019

отказ от ответственности: верно следующее для политики отслеживания изменений по умолчанию (неявно)

flush по определению записывает любые изменения, сделанные в управляемых объектах, в базу данных.

Сохранение сущности делает ее управляемой и, таким образом, любые изменения в ней, даже если они должны быть «временными», будут сохраняться на flush (как А.Марван уже указывал в комментарии).

Поскольку семантика очень ясна, я бы посоветовал не устанавливать временные значения для полей, которые управляются (любое сопоставленное поле). Либо добавьте временное свойство для этого, либо переоцените подход - возможно, службу или оболочку, либо что-либо еще, более подходящее вашему варианту использования.


комментарий для изменения политики отслеживания:

Ответ Rikudou_Sennin предлагает технически правильное решение технической проблемы, при котором сущности сохраняются, когда разработчик может этого не хотеть ... путем изменения политики отслеживания изменений. ИМХО, это семантически зло , ... хорошо, давайте назовем это проблематичным.

Как разработчик, я бы всегда предполагал, что объекты имеют согласованное состояние - даже если они еще не сброшены в базу данных. Если он имеет состояние, отличное от его постоянной версии, я хочу предположить, что когда запрос выполнен, и все или никакие измененных объектов записаны в базу данных, база данных находится в согласованном состоянии. государство. «Нет» можно считать данным. «Все» достаточно сложно обдумать.

Однако, с другой политикой отслеживания изменений и неявной возможностью, что «грязный» никогда не заслуживающий доверия объект может вращаться со значениями, на которые разработчик никак не может положиться, потому что неясно, если объект будет сохраняться или нет, или, возможно, был сохранен. Это только добавляет больше (ненужных) сомнений. Это также является дополнительным источником трудных для отладки ошибок.

Сводка опций:

  • добавление временного поля (или дополнительного var / object или чего-либо еще): разумные усилия и не влияющие на семантику (и предположения) *
  • изменение политики отслеживания и неправильное использование поля: низкие усилия при первом использовании, неизвестные (возможно, непостижимые) будущие усилия (и), потеря семантики и допущений (должны требовать явно заявленных гарантий, и даже тогда!).

*) предполагает несколько чистый и правильно структурированный код с неповрежденной и бескомпромиссной семантикой.

...