我怎样才能防止不需要的学说在 symfony 4 中持续存在?

How can I prevent unwanted doctrine persists in symfony 4?

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

我有一个名为 Field 的实体。它有一个 属性 数据表,带有常用的 getter 和 setter 方法。在我的支持 classes 之一中,我使用 setter 方法将 dataTable 更改为临时值。我从不在这个 class 或调用它的控制器中调用 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;
    }

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

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

持久化一个实体使其得到管理,因此对其进行的任何更改,即使它们本来是 "temporary" 也会在 flush 上持久化(正如 A.Marwan 已经指出的那样一条评论)。

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


更改跟踪政策的评论:

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

作为一名开发人员,我总是假设对象具有一致的状态 - 即使它尚未刷新到数据库。如果它的状态与其持久版本不同,我想假设,当请求完成时,all 或 none 已更改的对象被写入数据库,数据库处于一致状态。 "None" 可以假设给出。 "All" 想想就够难的了。

然而,使用不同的更改跟踪策略和隐含的可能性,"dirty" 永远不会被信任的对象可能会旋转,其值开发人员不能以任何方式依赖,因为它不清楚,如果对象将被持久化或不被持久化,或者可能被持久化。这只会增加更多(不必要的)疑虑。它还是难以调试错误的另一个来源。

选项汇总:

  • 添加临时字段(或额外的 var/object 或其他):合理的努力并且对语义(和假设)没有影响*
  • 更改跟踪策略和误用字段:首次使用工作量低,未知(可能难以理解)未来工作量,语义和假设的丢失(应该需要明确声明的保证,即使那样!)。

*) 假设有点 干净且结构正确的代码,具有完整和不妥协的语义。

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