使用 preRemove/postRemove 事件来获取哪些查询可以执行,哪些不能执行

2024-02-11

我在脑海中思考这个问题有一段时间了,现在我需要一些关于 preRemove/postRemove 事件的建议,因为我将执行的查询基本上是DELETE但这也应该适用于 prePersist/postPersist 和 preUpdate/postUpdate (不知道那些最新的是否真的存在)。

我有两种可能的情况在多个实体中执行 DELETE (请参阅foreach loop):

// First approach
$itemsRemoved = $itemsNonRemoved = [];
foreach($someVar as $item) {
    $item = $em->getRepository('someEntity')->find($item['value']);
    try {
        $em->remove($item);
        $em->flush();
        array_push($itemsRemoved, $item['value']);
    } catch (Exception $e) {
        dump($e->getMessage());
        array_push($itemsNonRemoved, $item['value']);
    }
}

// Second approach
$itemsRemoved = $itemsNonRemoved = [];
foreach($someVar as $item) {
    $item = $em->getRepository('someEntity')->find($item['value']);
    $em->remove($item);
}

$em->flush();

不推荐第一种方法,也可以@acontell用户说this https://stackoverflow.com/questions/27988758/difference-between-call-flush-inside-foreach-loop-or-outside-it-which-one-to回答执行flush()是一种反模式,也会影响应用程序性能,因为每次都需要执行多个查询,但使用这种方法我可以知道哪个查询被插入,哪个查询没有插入。

使用第二种方法,我将避免反模式并提高性能,但我如何知道哪个项目已插入,哪个没有插入?另外,如果默认情况下任何查询失败,Doctrine 都会进行回滚,因此不会插入任何查询。

那么,我可以使用 preRemove/postRemove 事件来获取哪些查询可以执行,哪些查询不能意味着插入或不插入哪些值吗?

这个问题与this https://stackoverflow.com/questions/27988758/difference-between-call-flush-inside-foreach-loop-or-outside-it-which-one-to and this https://stackoverflow.com/questions/28079661/delete-row-from-related-entity-in-many-to-many-relationship-in-doctrine2 ones.

现实生活中的例子

Since @acontell给我另一个很好的答案,我需要一些建议来看看我是否得到了全部内容,或者我仍然迷失了所以这里是一个现实生活中的例子:

        foreach ($request->request->get( 'items' ) as $item) {
            $relacion = $this->get( 'database_connection' )->fetchColumn(
                'SELECT COUNT(fabricante_producto_solicitud_id) AS cnt FROM negocio.fabricante_modelo_marca_producto WHERE fabricante_producto_solicitud_id = ?',
                array( $item['value'] )
            );               

            if ($relacion === 0) {
                $entFabricanteProductoSolicitud = $em->getRepository(
                    "AppBundle:FabricanteProductoSolicitud"
                )->find( $item['value'] );

                try {
                    $em->remove( $entFabricanteProductoSolicitud );
                    $em->flush();
                    array_push( $itemsRemoved, $item['value'] );

                    $response['success'] = true;
                    $status              = 200;
                } catch ( \Exception $e ) {
                    $status = 400;
                    dump( $e->getMessage() );

                    return new JsonResponse( $response, $status ?: 200 );
                }
            }

            $response['itemsRemoved'] = $itemsRemoved;
        }
    }

如果我得到它,那么LifeCycleCallbacks应该进去AppBundle:FabricanteProductoSolicitud在哪里执行 DELETE,是吗?

EDIT: 另外,我想知道在多个实体上使用代码的最佳方法,因为我在大多数实体中都会有这种行为,那么为此目的定义一个 Trait 应该没问题吗?应该被定义为任何其他特征吗?

这已得到答复here https://stackoverflow.com/a/28111353/719427我自己使用用户评论作为输入,希望它可以帮助其他人

由 @acontell 对代码执行一些测试

这就是我的代码此时的样子:

public function eliminarNormasAction(Request $request)
{
    if ($request->isXmlHttpRequest()) {
        $em = $this->getDoctrine()->getManager();
        $response['success']  = false;
        $entProducto = $em->getRepository('AppBundle:Producto')->find($request->request->get('producto'));
        $response['success']  = false;
        $status = null;

        $ids = [];
        foreach($request->request->get( 'items' ) as $item) {
            array_push( $ids, $item['value'] );
        }

        $qb = $em->createQueryBuilder();
        $entNorma = $qb
            ->select("q")
            ->from('AppBundle:Norma', 'q')
            ->add('where', $qb->expr()->in('q.id', ':ids'))
            ->setParameter('ids', $ids)
            ->getQuery()
            ->getResult();

        // Initialize arrays (useful to reset them also)
        Entity\Producto::prepareArrays();

        foreach($entNorma as $norma) {
            // here entities are persisted since rows there is not more at DB
            $entProducto->removeProductoNorma( $norma );  
        }

        try {
            $em->flush();
            $response['success'] = true;
        } catch (\Exception $e) {
            $status = 400;
        }

        $response['itemsRemoved']    = Entity\Producto::getDeletedEntities();
        $response['itemsNonRemoved'] = Entity\Producto::getNotDeletedEntities();
    } else {
        $response['error'] = $this->get('translator')->trans('mensajes.msgPeticionXMLHttpRequestInvalida');
    }

    return new JsonResponse($response, $status ?: 200);
}

问题Entity\Producto::getDeletedEntities()返回一个没有删除值的空数组,为什么?


我就是这样做的。我并不是说这是最好的方法,如果有人知道更简单或更好的东西,我将是第一个有兴趣学习它的人。

首先,这些是教义事件 http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#lifecycle-events您可以使用。为了简单起见,我将解释如何进行删除。另外为了简单起见,我将使用静态数组(可以通过其他方式完成,我喜欢这个)并且生命周期回调 http://symfony.com/doc/current/book/doctrine.html#lifecycle-callbacks。在这种情况下,回调将是非常简单的方法(这就是为什么可以使用它们而不是实现听众或订阅者 http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html).

假设我们有这个实体:

Acme\MyBundle\Entity\Car:
    type: entity
    table: cars
    id:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
    fields:
        name:
            type: string
            length: '25'
            unique: true
        color:
            type: string
            length: '64'
    lifecycleCallbacks:
        preRemove: [entityDueToDeletion]
        postRemove: [entityDeleted]

如您所见,我定义了两个将由 preRemove 事件和 postRemove 事件触发的回调。

preRemove - 给定实体的 preRemove 事件发生在 执行该实体的相应 EntityManager 删除操作。 DQL DELETE 语句不会调用它。

postRemove - postRemove 事件发生在实体 实体已被删除。数据库删除后会调用 运营。 DQL DELETE 语句不会调用它。

然后实体的php代码:

class Car {

    // Getters & setters and so on, not going to copy them here for simplicity

    private static $preDeletedEntities;// static array that will contain entities due to deletion.
    private static $deletedEntities;// static array that will contain entities that were deleted (well, at least the SQL was thrown).

    public function entityDueToDeletion() {// This callback will be called on the preRemove event
        self::$preDeletedEntities[] = $this->getId();// This entity is due to be deleted though not deleted yet.
    }

    public function entityDeleted() {// This callback will be called in the postRemove event
        self::$deletedEntities[] = $this->getId();// The SQL to delete the entity has been issued. Could fail and trigger the rollback in which case the id doesn't get stored in the array.
    }

    public static function getDeletedEntities() {
        return array_slice(self::$preDeletedEntities, 0, count(self::$deletedEntities));
    }

    public static function getNotDeletedEntities() {
        return array_slice(self::$preDeletedEntities, count(self::$deletedEntities)+1, count(self::$preDeletedEntities));
    }

    public static function getFailedToDeleteEntity() {
        if(count(self::$preDeletedEntities) == count(self::$deletedEntities)) {
            return NULL; // Everything went ok
        }
        return self::$preDeletedEntities[count(self::$deletedEntities)]; // We return the id of the entity that failed.
    }

    public static function prepareArrays() {
        self::$preDeletedEntities = array();
        self::$deletedEntities = array();
    }
}

请注意回调以及静态数组和方法。每次通过 a 调用删除Car实体,即preRemove回调会将实体的 id 存储在数组中$preDeletedEntities。当实体被删除时,postRemove事件会将 id 存储在$entityDeleted. The preRemove事件很重要,因为我们想知道哪个实体导致交易失败。

现在,在控制器中我们可以这样做:

use Acme\MyBundle\Entity\Car;

$qb = $em->createQueryBuilder();
$ret = $qb
        ->select("c")
        ->from('AcmeMyBundle:Car', 'c')
        ->add('where', $qb->expr()->in('c.id', ':ids'))
        ->setParameter('ids', $arrayOfIds)
        ->getQuery()
        ->getResult();

Car::prepareArrays();// Initialize arrays (useful to reset them also)
foreach ($ret as $car) {// Second approach
    $em->remove($car);
}

try {
    $em->flush();
} catch (\Exception $e) {
    $couldBeDeleted = Car::getDeletedEntities();
    $entityThatFailed = Car::getFailedToDeleteEntity();
    $notDeletedCars = Car::getNotDeletedEntities();

    // Do what you please, you can delete those entities that didn't fail though you'll have to reset the entitymanager (it'll be closed by now due to the exception).

    return $this->render('AcmeMyBundle:Car:errors.html.twig', array(// I'm going to respond with the ids that could've succeded, the id that failed and those entities that we don't know whether they could've succeeded or not.
                'deletedCars' => $couldBeDeleted,
                'failToDeleteCar' => $entityThatFailed,
                'notDeletedCars' => $notDeletedCars,
    ));
}

希望能帮助到你。它的实现比第一种方法要麻烦一些,但在性能方面要好得多。

UPDATE

我将尝试更多地解释一下内部发生的事情catch block:

至此,交易失败。由于无法删除某些实体(例如由于 fk 约束),因此引发了异常。

事务已回滚,并且实际上没有从数据库中删除任何实体。

$deletedCars是一个变量,其中包含那些本来可以被删除(它们没有引发任何异常)但没有(因为回滚)的实体的 id。

$failToDeleteCar包含其删除引发异常的实体的 ID。

$notDeletedCars包含事务中的其余实体 ID,但我们不知道是否会成功。

此时,您可以重置实体管理器(它已关闭),使用不会导致问题的 id 启动另一个查询并删除它们(如果您愿意),然后发回一条消息,让用户知道您删除了这些实体,并且$failToDeleteCar失败且未被删除$notDeletedCars也没有被删除。由您决定要做什么。

我无法重现你提到的问题Entity::getDeletedEntities(),这里工作正常。

您可以优化代码,以便不需要将此方法添加到实体(甚至不需要生命周期回调)。例如,您可以利用订阅者来捕获事件,并使用具有静态方法的特殊类来跟踪那些未失败的实体、失败的实体以及那些没有机会被删除的实体/更新/插入。我建议您参考我提供的文档。这比听起来要复杂一些,无法在几行代码中为您提供通用答案,抱歉,您必须进一步调查。

我的建议是您尝试使用我提供的假实体代码并进行一些测试以完全理解它是如何工作的。然后您可以尝试将其应用到您的实体中。

祝你好运!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 preRemove/postRemove 事件来获取哪些查询可以执行,哪些不能执行 的相关文章

  • Flask-login:无法理解它是如何工作的

    我试图理解如何Flask Login https flask login readthedocs org en latest works 我在他们的文档中看到他们使用预先填充的用户列表 我想使用数据库存储的用户列表 但是 我不明白其中的一些
  • PHP:读取所有传入 HTTP 请求的类 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 您的要求无法解析为 laravel 的一组可安装软件包

    我使用 5 7v Laravel 和 7 2 1v PHP 和 Composer 最新版本 但是当我想创建新项目时出现这些错误 Your requirements could not be resolved to an installabl
  • 如何将ElasticSearch与MySQL集成?

    在我的一个项目中 我计划将 ElasticSearch 与 MySQL 结合使用 我已经成功安装ElasticSearch 我可以单独管理ES中的索引 但我不知道如何用 MySQL 实现同样的功能 我读过一些文件 但我有点困惑 没有明确的想
  • 使用 PHP/linux 将文件合并为单个 PDF

    我正在研究如何将多个 PDF 合并为一个 PDF 我正在寻找一个图书馆可靠且坚固尽可能 最好有一个库可以保留书签 鬼脚本 http pages cs wisc edu ghost 可以在保存书签的位置进行连接 但我遇到了麻烦 在一种情况下它
  • 如何在 JavaScript 中创建服务器端进度指示器?

    我想在我的网站中创建一个部分 用户可以在其中进行一些简单的操作update纽扣 这些中的每一个update按钮将发送到服务器 并在幕后进行长时间的处理 当服务器处理数据时 我希望用户有某种进度指示器 例如进度条或文本百分比 我使用 jQue
  • PDO PHP 连接,致命错误

    我的连接类 firstcode php class DB functions public db function construct try db new PDO mysql localhost dbname xxx charset ut
  • 如何将表中不存在但原始SQL中存在的实体字段设置为别名?

    假设我们有一个这样的查询 SELECT CUSTOM EXPRESSION as virtualfield FROM users 用户的实体本身具有 虚拟字段 但映射注释没有 因为表没有该字段 假设它作为原始 SQL 执行 我们如何使用上面
  • 如何在 Play java 中创建数据库线程池并使用该池进行数据库查询

    我目前正在使用 play java 并使用默认线程池进行数据库查询 但了解使用数据库线程池进行数据库查询可以使我的系统更加高效 目前我的代码是 import play libs Akka import scala concurrent Ex
  • Java JDBC:更改表

    我希望对此表进行以下修改 添加 状态列 varchar 20 日期列 时间戳 我不确定该怎么做 String createTable Create table aircraft aircraftNumber int airLineCompa
  • 在 PHP 字符串中格式化 MySQL 代码

    是否有任何程序 IDE 可以在 PHP 字符串中格式化 MySQL 代码 例如 我使用 PHPStorm IDE 但它无法做到这一点 它对 PHP 和 MYSQL 执行此操作 但不适用于 php 字符串内的 MYSQL 我已准备好使用新的
  • 同一配置文件上的两个不同提供程序

    我在用着实体框架 6 1 0 I have 2 家提供者 MysqlClient 和 SQLServerCE 我需要创建2个不同的DBContext 这迫使我创造2个配置类因为mysql有一些不同的东西 但是当我初始化应用程序时 Datab
  • 如何处理 REST api 中的 php 通知、警告和错误?

    在 REST API 中 200 响应表明操作成功 PHP 默认情况下直接在响应正文中输出错误消息 而不更改响应代码 在 SPA 中 用户无法直接看到响应文本 因此 当应用程序未按预期工作时 我通过 FireBug 检查响应正文 以检查可能
  • 雄辩的第一个 where 子句

    我想知道 Laravel 如何实现雄辩的语法 以便可以静态调用第一个 where 子句User where User where id 23 gt where email email gt first 他们有吗public static f
  • 使用 php/regex 验证美国电话号码

    EDIT 我混合并修改了下面给出的两个答案 以形成完整的功能 现在它可以完成我想要的功能 然后是一些 所以我想我会将其发布在这里 以防其他人来寻找同样的东西 Function to analyze string against many p
  • PHP 表单 - 带验证蜜罐

    我有以下内容 效果很好 但对垃圾邮件机器人开放 我想放入蜜罐 而不是验证码 下面的代码适用于验证姓名 电子邮件 消息 但我无法让它与蜜罐一起工作 任何人都可以查看 蜜罐 代码并告诉我如何修复它吗 我希望表单给出 success2 不允许垃圾
  • 在本地 SDK 服务器上工作时,实时 Google App Engine 上出现 404

    我已经在GAE标准环境上部署了几个PHP应用程序 一切正常 现在我正在部署一个新应用程序 该应用程序位于由gcloudSDK按预期工作 终端命令 dev appserver py log level warning app yaml 问题是
  • Laravel 搜索关系

    我有两个相关的模型 我正在尝试在产品中进行搜索 并且仅显示实际搜索结果 而不是找到该产品的类别的所有产品 我不想搜索任何类别 因为无论搜索什么或找到什么 类别都会始终显示 Example I have the following categ
  • 如何在 PHP 5.6 中通过 php.ini 设置“verify_peer_name=false”SSL 上下文选项

    案例 我想打开 SSL 连接localhost而 SSL 证书是 FQDN 的问题 问题 没有进行特殊处理就行 下面的程序失败并显示以下消息 PHP Warning stream socket enable crypto Peer cert
  • PayPal 网关已拒绝请求。安全标头无效(#10002:安全错误 Magento

    在 magento 中增加 PayPal 预付款 我已填写 magento admin 中的所有凭据 但是当我进入前端并单击 pay pal 按钮时 它给出了 PayPal 网关已拒绝请求 安全标头无效 10002 安全错误 我用谷歌搜索了

随机推荐

  • <导航> 或 <菜单> (HTML5)

    W3Schools com 并且我很确定我记得看到过 W3C org 声明 menu 应用于工具栏菜单和列表表单控制命令 那么 我的主菜单应该使用哪一个呢 Nav or Menu 有关系吗 nav用于内部链接组 a元素 一般来说 这意味着链
  • PDFBox - 获取单词位置(而不仅仅是字符)

    是否可以使用 PDFBox 获取单词的位置 类似于 processTextPosition 似乎 processTextPosition 仅在单个字符上调用 将它们合并为单词的代码是 PDFTextStripper 在 规范化 中 方法的一
  • PHP SQL:如果变量为空则跳过查询部分的方法

    我正在编写一个查询 该查询使用搜索表单中的输入 其中品牌 类型和价格是可选输入字段 SELECT FROM database WHERE brand LIKE brand AND type LIKE type AND price LIKE
  • 配置选项错误:\377\376h

    我正在将我的系统设置为代码提交 但出现以下错误 我点击了以下链接 https docs aws amazon com codecommit latest userguide setting up ssh windows html https
  • 当服务器发送 HTML 而不是图像数据时,是否可以捕获失败的 IMG 加载?

    我有一个网站链接到其他网站上的不同图像 有时这些图像已被删除或域不再存在等 为了不显示这些图像并删除它们 我使用 jQuery 来执行此操作 catch image load errors img error function read o
  • Swift 1.2 中的 @noescape 属性

    Swift 1 2 中有一个新属性 在函数中带有闭包参数 正如文档所述 这表明 参数仅被调用 或作为 noescape 调用中的参数 这意味着它不能 比调用的生命周期更长 据我了解 在此之前 我们可以使用 weak self 不要让闭包有强
  • 如何从 TFS 控制下的项目中删除空文件夹?

    假设我有一个项目 MyLib 在该项目下 我创建了一个文件夹 例如Folder1 该文件夹下没有文件 该项目已连接到 TFS 然后我想删除这个文件夹Folder1 我从上下文菜单中删除了它 并将项目签入 TFS 然后我使用 Team Exp
  • 传递给函数的原始变量名? [复制]

    这个问题在这里已经有答案了 可能的重复 PHP 获取作为参数传递的变量的名称 https stackoverflow com questions 2379166 php get name of variable passed as argu
  • 服务层是否应该接受来自控制器的 DTO 或自定义请求对象?

    正如标题所示 设计服务层时的最佳实践是什么 我确实理解服务层应该始终返回 DTO 以便域 实体 对象保留在服务层中 但是控制器向服务层的输入应该是什么 下面我提出三点我自己的建议 方法一 在此方法中 域对象 Item 保留在服务层内 cla
  • PowerMock 测试通过然后失败

    为什么我的单元测试在独立运行时通过 但在运行多个测试时失败 当我执行单个单元测试时 我的测试将成功模拟并返回预期结果 但是 当我运行所有单元测试时 我之前通过的测试将失败 一次试运行 shouldDoThisAgain 通过 多次测试运行
  • Linq:GroupBy、Sum 和 Count

    我有一系列产品 public class Product public Product public string ProductCode get set public decimal Price get set public string
  • 在Java中生成数百万个不重复的随机数

    我有一个问题 我可以使用什么算法在Java中生成一组2 21随机唯一数字 java中除了math random之外还有另一个生成随机数的库吗 提前致谢 关键问题是你所说的 数字 是什么意思 一般来说 这个问题可以通过 生成一个数字列表 将其
  • 将整个文件夹从 Windows 移动到 Android 模拟器

    是否可以将整个文件夹按原样从 Windows 移动到 Android 模拟器 我确信这个问题的答案存在于某处 但我无法找到它 我可以通过 adb 命令行或通过 ddms 一次移动一个文件 但都没有给我提供移动包含多个文件夹和文件的整个文件夹
  • 表单标签可以包含正文标签吗?

    今天我遇到一些代码 在正文标签开始之前有一个表单标签 我的意思是 表单标签包含在正文标签中 这可能吗 如果是的话 它有什么帮助呢
  • 如何使用 Unix 变量在会话 {bash} 中设置和保留值 [重复]

    这个问题在这里已经有答案了 我需要做这样的事情 设置一个带有默认值的 unix 变量 运行一个 shell 脚本来读取该变量并对其进行处理 处理后可能会也可能不会改变该变量的值 每小时运行此脚本并确保此变量现在的值是上次运行此脚本时设置的值
  • 使用 PHP 获取/读取 Javascript cookie

    我有一个理论问题 我知道你可以使用 javascript 获取 读取 PHP cookie 文档 cookie PHP 中有类似的方法吗 PHP 可以获取 读取在 JavaScript 中创建的 cookie 吗 如果是 那么你怎么能这样做
  • 为什么 ENUM 在 MySQL 中不存储多个值?

    我想用ENUM表中的特征使用MySQL 我创建了一个表tbl test having id作为主键和enum col字段为ENUM数据类型 CREATE TABLE tbl test id INT NOT NULL AUTO INCREME
  • 具有相同工作空间的 2 个 Eclipse 版本

    目前 我的系统上正在运行 Eclipse Ganymede 我想安装 Eclipse Indigo 并将其连接到同一工作区 然后删除 Eclipse Ganymede 这可以正常工作还是我应该重新创建所有项目 理论上它应该有效 在实践中 我
  • Spring Cloud Sleuth 与 OpenTracing

    有没有办法将 Spring Cloud Sleuth 与 OpenTracing 结合使用 我想将 Spring 客户端与 Jaeger 连接 Spring Sleuth 现在与 OpenTracing 兼容 您所要做的就是在类路径中使用
  • 使用 preRemove/postRemove 事件来获取哪些查询可以执行,哪些不能执行

    我在脑海中思考这个问题有一段时间了 现在我需要一些关于 preRemove postRemove 事件的建议 因为我将执行的查询基本上是DELETE但这也应该适用于 prePersist postPersist 和 preUpdate po