2016-12-12 11 views
6

Tôi có một vấn đề lạ với \Doctrine\ORM\UnitOfWork::getScheduledEntityDeletions sử dụng bên trong onFlush kiệntổ chức theo lịch trình trong onFlush là khác nhau ví dụ

foreach ($unitOfWork->getScheduledEntityDeletions() as $entity) { 
    if ($entity instanceof PollVote) { 
     $arr = $entity->getAnswer()->getVotes()->toArray(); 

     dump($arr); 
     dump($entity); 

     dump(in_array($entity, $arr, true)); 
     dump(in_array($entity, $arr)); 
    } 
} 

Và đây là kết quả:

dump() output

Vì vậy, chúng ta thấy rằng đối tượng là chỉ đến một trường hợp khác với bản gốc, do đó, in_array không còn mang lại kết quả mong đợi khi được sử dụng với so sánh thanh (AKA ===). Hơn nữa, đối tượng \DateTime trỏ đến một cá thể khác.

duy nhất có thể giải thích tôi thấy như sau (source):

Bất cứ khi nào bạn lấy một đối tượng từ học thuyết cơ sở dữ liệu sẽ giữ một bản sao của tất cả các thuộc tính và các hiệp hội bên trong UnitOfWork. Bởi vì các biến trong ngôn ngữ PHP phải chịu "copy-on-write", việc sử dụng bộ nhớ của một yêu cầu PHP chỉ đọc các đối tượng từ cơ sở dữ liệu giống như khi Doctrine không giữ bản sao biến này. Chỉ khi bạn bắt đầu thay đổi biến PHP sẽ tạo biến mới trong nội bộ tiêu thụ bộ nhớ mới.

Tuy nhiên, tôi không thay đổi bất cứ điều gì (ngay cả trường created được giữ nguyên). Các hoạt động chỉ được preformed trên thực thể là:

  1. \Doctrine\ORM\EntityRepository::findBy (lấy từ DB)
  2. \Doctrine\Common\Persistence\ObjectManager::remove (lập kế hoạch cho việc loại bỏ)
  3. $em->flush(); (kích hoạt đồng bộ hóa với DB)

Dẫn tôi suy nghĩ (tôi có thể sai) rằng phương pháp theo dõi thay đổi của Giáo Lý không liên quan gì đến vấn đề tôi đang gặp phải. Dẫn tôi đến câu hỏi sau:

  • điều này gây ra là gì?
  • Làm thế nào để kiểm tra một cách đáng tin cậy nếu một thực thể được lên kế hoạch xóa bên trong một bộ sưu tập (\Doctrine\Common\Collections\Collection::contains sử dụng in_array với so sánh nghiêm ngặt) hoặc các mục nào trong bộ sưu tập được lên lịch xóa?
+1

Có vẻ như tôi đã gặp sự cố tương tự ngày hôm nay. Bạn có xóa thực thể của mình một cách rõ ràng không? Hoặc nó được loại bỏ bởi thác? –

+0

@AndreyMischenko '\ Doctrine \ Common \ Persistence \ ObjectManager :: remove' được gọi trên thực thể được đề cập. Không có thác nào liên quan đến trường hợp của tôi – Xymanek

+0

@AndreyMischenko bạn có quản lý để tìm giải pháp không? – Xymanek

Trả lời

1

Vấn đề là khi bạn nói với học thuyết để loại bỏ thực thể, nó được xóa khỏi bản đồ sắc (here):

<?php 

public function scheduleForDelete($entity) 
{ 
    $oid = spl_object_hash($entity); 

    // .... 

    $this->removeFromIdentityMap($entity); 

    // ... 

    if (! isset($this->entityDeletions[$oid])) { 
     $this->entityDeletions[$oid] = $entity; 
     $this->entityStates[$oid] = self::STATE_REMOVED; 
    } 
} 

Và khi bạn làm $entity->getAnswer()->getVotes(), nó như sau:

  1. Tải tất cả phiếu bầu từ cơ sở dữ liệu
  2. Đối với mỗi phiếu bầu, hãy kiểm tra xem có trong bản đồ nhận dạng hay không, sử dụng tên cũ
  3. Nếu nó không được nhận dạng y map, tạo đối tượng mới

Cố gắng gọi $entity->getAnswer()->getVotes() trước khi xóa thực thể. Nếu vấn đề biến mất, thì tôi đúng. Nguyên nhân, tôi sẽ không đề nghị hack này như một giải pháp, chỉ để đảm bảo rằng chúng tôi hiểu những gì đang xảy ra dưới mui xe.

UPD thay vì $entity->getAnswer()->getVotes() bạn nên có lẽ foreach cho tất cả các phiếu bầu, vì lười tải. Nếu bạn chỉ cần gọi $entity->getAnswer()->getVotes(), Doctrine có thể sẽ không làm bất cứ điều gì, và sẽ tải chúng chỉ khi bạn bắt đầu lặp qua chúng.

+0

Bạn đã đúng. Khởi tạo bộ sưu tập trước khi xóa sẽ khắc phục sự cố. Nhưng nó cũng loại bỏ mục đã xóa khỏi bộ sưu tập. Điều này có nghĩa là tôi không thể tin tưởng vào bộ sưu tập trong người nghe vì nó không biết nếu nó được khởi tạo hay không .... – Xymanek

+0

Trong mọi trường hợp, bạn đã tìm ra nguyên nhân của sự cố để bạn giành được số tiền thưởng – Xymanek

+0

@Xymanek sử dụng sự kiện preRemove hoặc một cái gì đó như thế. Bạn đã không chia sẻ usecase của bạn, vì vậy rất khó để đề xuất bất cứ điều gì. –

0

Từ doc:

Nếu bạn gọi EntityManager và yêu cầu cho một thực thể với một ID cụ thể hai lần, nó sẽ trở lại cùng một ví dụ

Vì vậy, gọi hai lần findOneBy(['id' => 12]) nên kết quả trong hai trường hợp giống hệt nhau.

Vì vậy, tất cả phụ thuộc vào cách cả hai trường hợp được truy lục bởi Doctrine. Theo ý kiến ​​của tôi, số tiền bạn nhận được trong $ arr là từ một liên kết Một-nhiều trên số phiếu bầu trong thực thể Trả lời, kết quả trong một truy vấn riêng biệt (có thể là id IN (12)) bởi ORM.

Một điều bạn có thể thử là khai báo liên kết này là EAGER (fetch="EAGER"), nó có thể buộc ORM thực hiện truy vấn cụ thể và giữ nó trong bộ nhớ cache để lần thứ hai bạn muốn nhận nó. ?

Bạn có thể xem nhật ký và đăng chúng tại đây không? Nó có thể cho thấy một cái gì đó thú vị hoặc ít nhất là có liên quan để điều tra thêm.

+0

Bộ sưu tập các phiếu bầu ('getAnswer() -> getVotes()') không được khởi tạo trước khi được đưa vào mảng - có lẽ điều này có liên quan đến vấn đề này. Tôi đang chơi với một trường hợp thử nghiệm giảm ngay bây giờ, sẽ báo cáo lại khi tôi có một tập hợp các kết quả tốt – Xymanek

Các vấn đề liên quan