如何防止Symfony 4中不必要的学说继续存在?

时间:2019-04-24 12:50:27

标签: symfony doctrine symfony4

在这一点上,我不确定问题出在教义还是symfony。

我有一个名为Field的实体。它具有带有常规getter和setter方法的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);
}

设置功能:

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

2 个答案:

答案 0 :(得分:1)

免责声明:默认更改跟踪策略(隐式)适用以下条件

flush根据定义将对托管实体所做的所有更改都写入数据库。

持久存在一个实体可以对其进行管理和管理,因此对它的任何更改(即使它们被认为是“临时的”)也将保留在flush上(正如A.Marwan在评论中已经指出的那样)。

由于语义非常清晰,我建议不要在托管字段(即任何映射字段)上设置临时值。为此添加一个临时属性或重新评估该方法-可能是服务或包装器,或更适合您的用例的任何东西。


更改跟踪策略的评论:

Rikudou_Sennin的答案为技术问题提供了一种技术上正确的解决方案,即当开发人员可能不希望通过更改更改策略来使实体持久化时,实体将保持不变。恕我直言,这在语义上是邪恶,...好吧,我们称之为有问题。

作为开发人员,我将始终假定对象具有一致的状态-即使尚未刷新到数据库中。如果它的状态与其持久版本不同,我想假设当请求完成后,全部或全部的已更改对象都被写入数据库,则该数据库位于一致状态。可以假定为“无”。 “全部”很难思考。

但是,由于采用了不同的变更跟踪策略和隐性可能性,“肮脏的”永不被信任的对象可能会绕来绕去,开发人员无法以任何方式依赖该值,因为尚不清楚该对象是否将被持久化还是被持久化。这只会增加(不必要的)怀疑。这也是难以调试的错误的另一个来源。

选项摘要:

  • 添加一个临时字段(或其他var / object或其他内容):合理的努力,并且不会影响语义(和假设)*
  • 更改跟踪策略并滥用字段:较低的首次使用工作量,未来的未知工作量(可能是无法估量的),语义和假设的丢失(应该明确声明保证,甚至是这样!)。

*)假定有些干净且结构正确的代码,且语义完整无缺。

答案 1 :(得分:1)

您可以通过将Change Tracking PolicyDeferred 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