【问题标题】:Ignore missing entities in doctrine忽略学说中缺失的实体
【发布时间】:2015-09-21 20:42:35
【问题描述】:

我们正在将一个应用程序移植到 Symfony2 并且目前使用理论 ORM 卡住了。我们在数据库中有一堆错误的外键,并且在不遇到“找不到实体”异常的情况下进行关系映射变得越来越困难。它在清理数据库的路线图上,但不幸的是,这不是我们现在可以解决的问题。如果找不到正确的实体,有什么办法可以让它返回 null 吗?

如果我有如下关系映射:

    User:
      type: entity
      table: user
      id:
        userID:
          type: integer
          generator:
            strategy: NONE
      fields:
        contactName:
          type: string
          length: 255
          nullable: false
        contactPhone:
          type: string
          length: 255
          nullable: false
        companyName:
          type: string
          length: 255
          nullable: false
        username:
          type: string
          length: 255
          nullable: false
        password:
          type: string
          length: 255
          nullable: false
        email:
          type: string
          length: 255
          nullable: false
      manyToOne:
          address:
            targetEntity: Address
            joinColumn:
              name: addressID
              referencedColumnName: addressID
              nullable: true
              default: null



    -----------------------------------------------------

    Address:
      type: entity
      table: address
      id:
        addressID:
          type: integer
          generator:
            strategy: AUTO
      fields:
        street:
          type: string
          length: 255
          nullable: false
        street2:
          type: string
          length: 255
          nullable: false
        city:
          type: string
          length: 255
          nullable: false
        state:
          type: string
          length: 32
          nullable: false
        zip:
          type: string
          length: 10
          nullable: false
        country:
          type: string
          length: 40
          nullable: false

似乎如果用户表中的 addressID 值错误,我会得到“找不到实体”。通过序列化程序发送时出现异常。

【问题讨论】:

    标签: php symfony doctrine-orm


    【解决方案1】:

    是的,这完全有可能,但我很难告诉你具体怎么做,因为你没有提供任何例子。您能否提供一些现有的代码示例,以便我可以给您一些建议?

    顺便说一句,您可以像这样在存储库中进行查询:

    $qb = $this->entityManager->createQueryBuilder();
    $qb->select('e')
        ->from('MyBundle:Entity', 'e')
        ->where($qb->expr()->eq('e.id', ':id'))
        ->setParameter('id', 1)
        ->setMaxResults(1);
    
    $result = $qb->getQuery()->getOneOrNullResult();
    

    如果未找到实体,则结果将包含 null。但我认为大多数 find* 方法将返回 null。检查 Doctrine2 中的 Repository 类。如果需要,您还可以扩展 Doctrine 的存储库并覆盖方法以防万一抛出异常。您可以捕获它并返回 null、空数组或任何手工制作的对象......等等。

    如果您正在执行任何联接,如果您不确定数据是否存在,也可以考虑使用左联接。同样在访问代码中的引用对象时,例如,如果您有:

    $user->getProfile();
    

    并且有可能返回null的危险,在返回对象之前检查方法本身,如下所示:

    public function getProfile()
    {
        if ($this->profile === null) {
            return new DummyProfile();
        }
    
        return $this->profile;
    }
    

    DummyProfile 可以扩展您的原始 Profile 对象,它可以像一个模拟对象,返回一些默认值。您也可以将这个虚拟对象保存在一个属性中并在下次返回它,因此它不会一直实例化(单例模式)。这是保护代码的方法,因此您最终不会在 null 上调用方法,这会导致 php 错误。

    希望这能让您知道如何继续... :)

    【讨论】:

    • 感谢您的快速响应!不幸的是,您在返回属性值之前检查 null 的建议没有奏效。我仍然收到“找不到实体”。例外。
    • 抱歉,这是一个糟糕的建议 - 找不到实体的原因是 Doctrine / Symfony 将实体从模型中加载出来,首先检查 null 不会阻止这一点,尤其是因为它的关键不是 null 导致 Symfony / Doctrine 尝试加载它的事实!
    【解决方案2】:

    啊,这也是我们经常看到的 PITA。如果你禁用了延迟加载,那么 Doctrine 可能会在当时加载和水合所有链接的实体。但我猜当您尝试在 Symfony 中渲染模板/表单时,它会打开并死掉。

    启用延迟加载后,您在加载实体时不会收到错误消息,但是如果您尝试访问相关实体的属性(这将导致 Doctrine 加载它)或渲染,则会收到错误消息symfony 表单中的实体和表单上的字段与外部表的属性相关。

    不幸的是,没有简单的方法可以阻止或抓住这一点。我的建议是手动检查数据中是否有错误的外键并清理数据,Doctrine 的延迟加载对错误数据特别无情,而 Symfony 只会在遇到 duff 链接时引发错误 500,从而使情况变得更糟。

    【讨论】:

      【解决方案3】:

      我刚遇到同样的问题,在寻找解决方案时发现了这个问题......我没有找到。这是我所做的(使用注释):

      1. 让关系变得懒惰:

        /**
         * @var Resource
         *
         * @ORM\JoinColumn(name="ResourceID", referencedColumnName="ResourceID")
         * @ORM\OneToOne(targetEntity="Resource", fetch="LAZY")
         */
         private $resource;
         private $_resource_is_valid = null;
        
      2. 修改 getter 并始终使用它 -- 甚至在类内部:

         /**
          * Returns the associated resource, accounting for bad references.
          * @return Resource|null
          */
         public function getResource()
         {
             if (is_null($this->_resource_is_valid))
             {
                 try
                 {
                     // We need to call a method that triggers a lazy load
                     if ($this->resource && $this->resource->getID())
                     {
                         $this->_resource_is_valid = true;
                     }
                 }
                 catch (\Doctrine\ORM\EntityNotFoundException $enf)
                 {
                     $this->_resource_is_valid = false;
                     // consider creating a new resource object.
                 }
             }
             if ($this->_resource_is_valid)
             {
                 return $this->resource;
             }
             return null;
         }
        

      这种方法允许 Doctrine 对实体进行部分水合,并让您将不良关系困在您拥有更多控制权的区域。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多