2013-04-24 30 views
7

Trong Doctrine mới nhất trên Symfony2 cố gắng tìm ra nhiều mối quan hệ hai chiều giữa hai đối tượng.Doctrine multiple OneToMany/ManyToOne vi phạm ràng buộc toàn vẹn hai chiều

Đối tượng chủ sở hữu có một địa chỉ bưu chính và sau đó nhiều địa chỉ phụ trong bộ sưu tập và tôi xóa() Person, tôi muốn tất cả địa chỉ của nó cũng bị xóa (nhưng xóa địa chỉ sẽ không xóa một người), nhưng tôi nhận được lỗi này -

An exception occurred while executing 'DELETE FROM address WHERE id = ?' with 
params {"1":"fb5e47de-2651-4069-b85e-8dbcbe8a6c4a"}: 

[PDOException] SQLSTATE[23000]: Integrity constraint violation: 1451 
Cannot delete or update a parent row: a foreign key constraint fails 
(`db`.`address`, CONSTRAINT `FK_633704 C29C1004E` 
FOREIGN KEY (`person_id`) REFERENCES `person` (`id`)) 

trong

class Person 
{ 

    /** 
    * @var Address postalAddress 
    * 
    * @ORM\OneToOne(targetEntity="Address", cascade={"all"}, orphanRemoval=true) 
    * @ORM\JoinColumn(onDelete="cascade") 
    */ 
    private $postalAddress; 

    /** 
    * @var \Doctrine\Common\Collections\Collection otherAddresses 
    * 
    * @ORM\OneToMany(targetEntity="Address", mappedBy="person", cascade={"all"}, orphanRemoval=true) 
    */ 
    private $otherAddresses; 


} 

class Address 
{ 

    /** 
    * @var Person person 
    * 
    * @ORM\ManyToOne(targetEntity="Person", inversedBy="postalAddress, otherAddresses") 
    * @ORM\JoinColumn(nullable=false) 
    */ 
    private $person; 
} 

tôi nghĩ nó có thể vì

inversedBy="postalAddress, otherAddresses" 

Tôi không nghĩ rằng nhiều inversedBy được hỗ trợ; sau đó tôi cũng đã cố gắng thay đổi

@ORM\JoinColumn(nullable=false) 

để có thể vô hiệu, nhưng tôi vẫn gặp lỗi.

Điều này rõ ràng không phải là về ví dụ về người/địa chỉ tầm thường nhưng cái gì phức tạp hơn, nhưng đây là nỗ lực tốt nhất của tôi khi trừu tượng hóa.

Tôi chắc chắn tôi đã bỏ lỡ điều gì đó hiển nhiên. Có ai giúp được không?

+1

Tôi nghĩ rằng vấn đề có thể là bạn đang cố gắng nói rằng nhiều người được OneversOne đảo ngược chứ không phải là ManyToOne. Bạn đã thử '* @ORM \ ManyToOne (targetEntity =" Person ", inversedBy =" otherAddresses ") * @ORM \ OneToOne (targetEntity =" Person ") * @ORM \ JoinColumn (nullable = false)' Nó có thể thay đổi cách học thuyết xử lý các tầng, mặc dù nó không thay đổi lược đồ. –

Trả lời

2

bị hỏng Relational Definition

Trong khi những gì bạn đang làm có thể có ý nghĩa từ một quan điểm hoàn toàn hợp lý, nó không từ một quan điểm quan hệ dữ liệu, và đặc biệt là làm cho không có ý nghĩa theo quan điểm của học thuyết của.

thuyết đang cố gắng duy trì 3 mối quan hệ khác nhau:

  • Địa chỉ (sở hữu-side) [bi-directional] $ person --Many:One--> $ otherAddresses Person
  • Địa chỉ (sở hữu-side) [hai chiều] $ person --Many:One--> $ postalAddress Người
  • Người (sở hữu-side) [uni-directional] $ postalAddress --One:One--> $ id Địa chỉ

Bạn thấy vấn đề này?

Sử dụng các tiêu chuẩn quan hệ để giải quyết vấn đề này.

Giải pháp đơn giản ở đây là sử dụng mẫu thiết kế rất phổ biến của việc thiết lập chính cho một bộ sưu tập.Về bản chất, bạn chỉ cần một mối quan hệ:

  • Địa chỉ (sở hữu-side) [bi-directional] $ person --Many:One--> $ otherAddresses Person

Sau đó, thêm để giải quyết một tài sản mà xác định địa chỉ đó là chính. Programattically xử lý này trong các đối tượng Person và Địa chỉ:

Class Person 
{ 
    . . . 
    public function getPrimaryAddress() { 
     if (null === $this->primaryAddress) { 
      foreach($this->getOtherAddresses() as $address) { 
       if ($address->isPrimary()) { 
        $this->primaryAddress = $address; 
        break; 
       } 
      } 
     } 

     return $this->primaryAddress; 
    } 

    // similar for the setter, update the old address as not primary if there is one, set the new one as primary. 
} 

Sử dụng hai mối quan hệ khác nhau, nhưng không vượt qua con suối

Nếu bạn giữ cho One-to-One mối quan hệ một chiều từ người này sang địa chỉ , vấn đề giải quyết chính nó.

  • Địa chỉ (sở hữu-side) [bi-directional] $ person --Many:One--> $ otherAddresses Person
  • Person (sở hữu-side) [uni-directional] $ postalAddress --One:One-->Địa chỉ

Bạn vẫn sẽ gặp khó khăn ở đây mặc dù, vì Doctrine sẽ khiếu nại nếu: - chính (PostalAddress) địa chỉ không có cả hai mặt cho số Nhiều: Một được xác định. (do đó địa chỉ "chính" của bạn cũng sẽ phải nằm trong bộ sưu tập $otherAddresses). - cố gắng loại bỏ hoặc phân tầng xóa và cập nhật sẽ dẫn đến hai mối quan hệ xung đột, "qua suối" của các ràng buộc quan hệ của học thuyết, vì vậy bạn sẽ phải xử lý các hoạt động đó một cách có lập trình.

+0

Lưu ý: phương thức 'Person :: getPrimaryAddress' có thể được làm sạch hơn với tiêu chí. –

+1

oh người đàn ông, tôi hỏi điều này 4 năm trước đây. Bây giờ giải pháp là một chút rõ ràng hơn với tôi nhưng tại thời điểm tôi không chắc chắn. Cảm ơn bạn đã trả lời! – gingerCodeNinja

+1

Câu hỏi của bạn xuất hiện lần đầu tiên trong tìm kiếm của Google. Trong khi tôi nhận ra bạn đã tìm được cách giải quyết vấn đề của mình, tôi muốn giúp người lập kế hoạch bị mất tiếp theo tìm đường đến đây. –

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