- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这个问题在我脑海中盘旋了一段时间,现在我需要一些关于 preRemove/postRemove 事件的建议,因为我将执行的查询基本上是 DELETE
但这应该也适用于 prePersist/postPersist 和 preUpdate/postUpdate(不知道那些最新的是否真的存在)。
我在几个实体中执行 DELETE 有两种可能的情况(参见 foreach
循环):
// 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 上所说的那样answer execute flush()
是一种反模式,也会影响应用程序性能,因为每次都需要执行多个查询,但使用这种方法我可以得到哪个被插入,哪个没有被插入。
使用第二种方法我将避免反模式并提高性能,但我如何知道插入了哪些项目,哪些没有插入?此外,如果默认情况下任何查询失败,Doctrine 将进行回滚,因此不会插入任何查询。
那么,我是否可以使用 preRemove/postRemove 事件来获取哪些查询可以执行,哪些不能表示插入或不插入哪些值?
现实生活中的例子
既然 @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
应该放在执行 DELETE 的 AppBundle:FabricanteProductoSolicitud
中,对吗?
编辑:我还想知道在多个实体上使用代码的最佳方法,因为我在大多数实体中都会有这种行为,那么为此目的定义一个 Trait 应该没问题吧?应该定义为任何其他特征?
已回答here自己使用用户评论作为输入,希望它可以帮助别人
通过@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()
返回一个没有删除值的空数组,为什么?
最佳答案
这是我的做法。我并不是说这是最好的方法,如果有人知道更简单或更好的方法,我会是第一个有兴趣学习它的人。
首先,这些是 Doctrine events你可以使用。为了简单起见,我将解释如何进行删除。同样为了简单起见,我将使用一个静态数组(它可以通过其他方式完成,我喜欢这个)和 lifecycle callbacks .在这种情况下,回调将是非常简单的方法(这就是为什么可以使用它们而不是实现 listener or subscriber 的原因)。
假设我们有这个实体:
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 - The preRemove event occurs for a given entity before the respective EntityManager remove operation for that entity is executed. It is not called for a DQL DELETE statement.
postRemove - The postRemove event occurs for an entity after the entity has been deleted. It will be invoked after the database delete operations. It is not called for a DQL DELETE statement.
然后是实体的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();
}
}
注意回调以及静态数组和方法。每次通过 Car
实体调用 remove 时,preRemove
回调会将实体的 ID 存储在数组 $preDeletedEntities
中。当实体被删除时,postRemove
事件会将 id 存储在 $entityDeleted
中。 preRemove
事件很重要,因为我们想知道是哪个实体导致交易失败。
现在,在 Controller 中我们可以这样做:
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,
));
}
希望对您有所帮助。与第一种方法相比,实现起来有点麻烦,但在性能方面要好得多。
更新
我将尝试解释更多 catch
block 中发生的事情:
此时,交易已经失败。由于无法删除某些实体(例如由于 fk 约束)这一事实引发了异常。
事务已回滚,没有实体从数据库中实际删除。
$deletedCars
是一个变量,包含那些本来可以删除(它们没有引发任何异常)但没有删除(因为回滚)的实体的 ID。
$failToDeleteCar
包含删除引发异常的实体的 ID。
$notDeletedCars
包含交易中的其余实体 ID,但我们不知道是否会成功。
此时,您可以重置 entitymanager(它已关闭),使用没有引起问题的 ID 启动另一个查询并删除它们(如果您愿意)并发回一条消息让用户知道您删除了那些实体并且 $failToDeleteCar
失败并且未被删除,$notDeletedCars
也未被删除。由您决定要做什么。
我无法重现你提到的关于 Entity::getDeletedEntities()
的问题,它在这里工作正常。
您可以优化您的代码,这样您就不需要将此方法添加到您的实体(甚至生命周期回调)。例如,您可以使用一个订阅者来捕获事件和一个带有静态方法的特殊类来跟踪那些没有失败的实体、失败的实体和没有机会被删除的实体/更新/插入。请引用我提供的文档。它比听起来要复杂一些,无法通过几行代码给你一个通用的答案,抱歉,你必须进一步调查。
我的建议是您尝试我提供的带有假实体的代码,并进行一些测试以完全了解它的工作原理。然后您可以尝试将其应用于您的实体。
祝你好运!
关于php - 使用 preRemove/postRemove 事件来获取哪些查询可以执行,哪些不可以,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28097800/
我需要您在以下方面提供帮助。近一个月来,我一直在阅读有关任务和异步的内容。 我想尝试在一个简单的 wep api 项目中实现我新获得的知识。我有以下方法,并且它们都按预期工作: public Htt
我的可执行 jar 中有一个模板文件 (.xls)。不需要在运行时我需要为这个文件创建 100 多个副本(稍后将唯一地附加)。用于获取 jar 文件中的资源 (template.xls)。我正在使用
我在查看网站的模型代码时对原型(prototype)有疑问。我知道这对 Javascript 中的继承很有用。 在这个例子中... define([], function () { "use
影响我性能的前三项操作是: 获取滚动条 获取偏移高度 Ext.getStyle 为了解释我的应用程序中发生了什么:我有一个网格,其中有一列在每个单元格中呈现网格。当我几乎对网格的内容做任何事情时,它运
我正在使用以下函数来获取 URL 参数。 function gup(name, url) { name = name.replace(/[\[]/, '\\\[').replace(/[\]]/,
我最近一直在使用 sysctl 来做很多事情,现在我使用 HW_MACHINE_ARCH 变量。我正在使用以下代码。请注意,当我尝试获取其他变量 HW_MACHINE 时,此代码可以完美运行。我还认为
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 关闭 9 年前。 要求提供代码的问题必须表现出对所解决问题的最低限度的理解。包括尝试过的解决方案、为什么
由于使用 main-bower-files 作为使用 Gulp 的编译任务的一部分,我无法使用 node_modules 中的 webpack 来require 模块code> dir 因为我会弄乱当
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 5 年前。 Improve this qu
我使用 Gridlayout 在一行中放置 4 个元素。首先,我有一个 JPanel,一切正常。对于行数变大并且我必须能够向下滚动的情况,我对其进行了一些更改。现在我的 JPanel 上添加了一个 J
由于以下原因,我想将 VolumeId 的值保存在变量中: #!/usr/bin/env python import boto3 import json import argparse import
我正在将 MSAL 版本 1.x 更新为 MSAL-browser 的 Angular 。所以我正在尝试从版本 1.x 迁移到 2.X.I 能够成功替换代码并且工作正常。但是我遇到了 acquireT
我知道有很多关于此的问题,例如 Getting daily averages with pandas和 How get monthly mean in pandas using groupby但我遇到
This is the query string that I am receiving in URL. Output url: /demo/analysis/test?startDate=Sat+
我正在尝试使用 javascript 中的以下代码访问 Geoserver 层 var gkvrtWmsSource =new ol.source.ImageWMS({ u
API 需要一个包含授权代码的 header 。这就是我到目前为止所拥有的: var fullUrl = 'https://api.ecobee.com/1/thermostat?json=\{"s
如何获取文件中的最后一个字符,如果是某个字符,则删除它而不将整个文件加载到内存中? 这就是我目前所拥有的。 using (var fileStream = new FileStream("file.t
我是这个社区的新手,想出了我的第一个问题。 我正在使用 JSP,我成功地创建了 JSP-Sites,它正在使用jsp:setParameter 和 jsp:getParameter 具有单个字符串。
在回答 StoreStore reordering happens when compiling C++ for x86 @Peter Cordes 写过 For Acquire/Release se
我有一个函数,我们将其命名为 X1,它返回变量 Y。该函数在操作 .on("focusout", X1) 中使用。如何获取变量Y?执行.on后X1的结果? 最佳答案 您可以更改 Y 的范围以使其位于函
我是一名优秀的程序员,十分优秀!