Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Sử dụng các sự kiện preRemove / postRemove để nhận được truy vấn nào có thể được thực thi và truy vấn nào không thể

Đây là cách tôi sẽ làm điều đó. Tôi không nói rằng đây là cách tiếp cận tốt nhất, nếu ai đó biết điều gì đó dễ dàng hơn hoặc tốt hơn, tôi sẽ là người đầu tiên quan tâm đến việc tìm hiểu nó.

Trước hết, đây là Sự kiện giáo lý mà bạn có thể sử dụng. Vì lý do đơn giản, tôi sẽ giải thích cách tôi làm điều đó để xóa. Ngoài ra, để đơn giản hơn, tôi sẽ sử dụng một mảng tĩnh (nó có thể được thực hiện theo một số cách khác, tôi thích cách này) và các lệnh gọi lại vòng đời . Trong trường hợp này, các lệnh gọi lại sẽ là các phương thức rất đơn giản (đó là lý do tại sao bạn có thể sử dụng chúng thay vì triển khai người nghe hoặc người đăng ký ).

Giả sử chúng ta có thực thể này:

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]

Như bạn có thể thấy, tôi đã xác định hai lệnh gọi lại sẽ được kích hoạt với sự kiện preRemove và sự kiện postRemove.

Sau đó, mã php của thực thể:

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();
    }
}

Lưu ý các lệnh gọi lại và các mảng và phương thức tĩnh. Mỗi lần xóa được gọi trên Car thực thể, preRemove callback sẽ lưu trữ id của thực thể trong mảng $preDeletedEntities . Khi thực thể bị xóa, postRemove sự kiện sẽ lưu trữ id trong $entityDeleted . preRemove sự kiện quan trọng vì chúng tôi muốn biết thực thể nào đã thực hiện giao dịch không thành công.

Và bây giờ, trong bộ điều khiển, chúng ta có thể làm điều này:

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,
    ));
}

Hy vọng nó giúp. Nó hơi rườm rà hơn để triển khai so với cách tiếp cận đầu tiên nhưng tốt hơn nhiều về mặt hiệu suất.

CẬP NHẬT

Tôi sẽ cố gắng giải thích thêm một chút về những gì đang mở ra bên trong catch khối:

Tại thời điểm này, giao dịch đã không thành công. Một ngoại lệ đã được đưa ra do thực tế là không thể xóa một số thực thể (ví dụ:do ràng buộc fk).

Giao dịch đã được khôi phục và không có yêu cầu nào thực sự bị xóa khỏi cơ sở dữ liệu.

$deletedCars là một biến có chứa id của những thực thể đó có thể đã bị xóa (chúng không đưa ra bất kỳ ngoại lệ nào) nhưng không phải (do quay trở lại).

$failToDeleteCar chứa id của thực thể mà việc xóa đã làm tăng ngoại lệ.

$notDeletedCars chứa phần còn lại của id thực thể đã có trong giao dịch nhưng chúng tôi không biết khi nào thì sẽ thành công hay không.

Tại thời điểm này, bạn có thể đặt lại trình quản lý thực thể (nó đã đóng), khởi chạy một truy vấn khác với các id không gây ra sự cố và xóa chúng (nếu bạn muốn) và gửi lại thông báo cho người dùng biết rằng bạn đã xóa các thực thể đó và $failToDeleteCar không thành công và không bị xóa và $notDeletedCars cũng không bị xóa. Bạn quyết định phải làm gì.

Tôi không thể tái tạo sự cố bạn đề cập về Entity::getDeletedEntities() , nó hoạt động tốt ở đây.

Bạn có thể tinh chỉnh mã của mình để không cần thêm các phương thức này vào các thực thể của mình (thậm chí không phải các lệnh gọi lại vòng đời). Ví dụ:bạn có thể sử dụng người đăng ký để nắm bắt các sự kiện và một lớp đặc biệt với các phương thức tĩnh để theo dõi những thực thể không bị lỗi, thực thể bị lỗi và những thực thể không có cơ hội bị xóa / cập nhật / chèn. Tôi giới thiệu bạn với tài liệu tôi đã cung cấp. Nó phức tạp hơn một chút so với âm thanh của nó, không thể cung cấp cho bạn câu trả lời chung trong một vài dòng mã, xin lỗi, bạn sẽ phải điều tra thêm.

Đề xuất của tôi là bạn thử mã mà tôi đã cung cấp với một thực thể giả mạo và thực hiện một số thử nghiệm để hiểu đầy đủ cách hoạt động của nó. Sau đó, bạn có thể thử áp dụng nó cho các thực thể của mình.

Chúc bạn thành công!




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tại sao truy vấn này không tạo ra kết quả mysql_error ()?

  2. Lược đồ cơ sở dữ liệu tình bạn một hàng với việc lấy lưới sử dụng từ cột này hoặc cột khác

  3. CHAR () hoặc VARCHAR () làm khóa chính trong bảng ISAM MySQL?

  4. Truy cập dữ liệu từ servlet

  5. Có gì sai với truy vấn UPDATE này?