Sự khác biệt giữa inversedBy và mappedBy là gì?


102

Tôi đang phát triển ứng dụng của mình bằng Zend Framework 2 và Doctrine 2.

Trong khi viết chú thích, tôi không thể hiểu sự khác biệt giữa mappedByinversedBy.

Khi nào tôi nên sử dụng mappedBy?

Khi nào tôi nên sử dụng inversedBy?

Khi nào tôi không nên sử dụng?

Đây là một ví dụ:

 /**
 *
 * @ORM\OneToOne(targetEntity="\custMod\Entity\Person", mappedBy="customer")
 * @ORM\JoinColumn(name="personID", referencedColumnName="id")
 */
protected $person;

/**
 *
 * @ORM\OneToOne(targetEntity="\Auth\Entity\User")
 * @ORM\JoinColumn(name="userID", referencedColumnName="id")
 */
protected $user;

/**
 *
 * @ORM\ManyToOne (targetEntity="\custMod\Entity\Company", inversedBy="customer")
 * @ORM\JoinColumn (name="companyID", referencedColumnName="id")
 */
protected $company;

Tôi đã tìm kiếm nhanh và tìm thấy thông tin sau, nhưng tôi vẫn còn nhầm lẫn:

Câu trả lời:


159
  • ánh xạBy phải được chỉ định ở phía đảo ngược của một liên kết (hai chiều)
  • inversedBy phải được chỉ định ở phía sở hữu của một liên kết (hai chiều)

từ tài liệu giáo lý:

  • ManyToOne luôn là mặt sở hữu của phân bổ hai chiều.
  • OneToMany luôn là mặt nghịch đảo của phân bổ hai chiều.
  • Phía sở hữu của một gán OneToOne là thực thể có bảng chứa khóa ngoại.

Xem https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html


1
Thật kỳ lạ, nhà lập tài liệu Doctrine quyết định loại bỏ ví dụ yaml về ánh xạ hai chiều nhiều-một, có lẽ là cách được sử dụng phổ biến nhất!
Peter Wooster

4
@PeterWooster, thực tiễn tốt nhất là sử dụng Chú thích, vì bạn có tất cả thông tin về đối tượng ở một nơi!
Andreas Linden

Điều này cũng áp dụng cho nhiều mối quan hệ. Đối với những người đó: bạn có thể tự mình chọn phe sở hữu của một hiệp hội nhiều người.
11 giờ trưa

5
@AndreasLinden được sử dụng rộng rãi không có nghĩa là phương pháp hay nhất. Một thứ gì đó sử dụng nhận xét để viết mã khi đang di chuyển không bao giờ được coi là phương pháp hay nhất, nó không phải là php native và thậm chí không được bao gồm theo mặc định trong tất cả các framework. Có tất cả thông tin về một thực thể ở một nơi là một lập luận chống đối. Vì khi nào nhóm tất cả mã của bạn vào một nơi là một điều tốt? Đó là một nỗi đau khi viết, một nỗi đau khi duy trì và giảm bớt tổ chức trong dự án của bạn. thực hành tốt nhất ? Tât nhiên.
JesusTheHun

4
@JesusTheHun bạn đang so sánh táo và lê. "tất cả mã" rất khác với "tất cả thông tin về một thực thể";)
Andreas Linden

55

Những câu trả lời trên không đủ để tôi hiểu chuyện gì đang xảy ra, vì vậy sau khi nghiên cứu kỹ hơn, tôi nghĩ rằng tôi có cách giải thích nó sẽ hợp lý cho những người đang đấu tranh như tôi có thể hiểu được.

inversedBy và mappedBy được sử dụng bởi công cụ INTERNAL DOCTRINE để giảm số lượng truy vấn SQL mà nó phải thực hiện để có được thông tin bạn cần. Để rõ ràng nếu bạn không thêm inversedBy hoặc mappedBy, mã của bạn sẽ vẫn hoạt động nhưng sẽ không được tối ưu hóa .

Ví dụ: hãy xem các lớp bên dưới:

class Task
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="task", type="string", length=255)
     */
    private $task;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="dueDate", type="datetime")
     */
    private $dueDate;

    /**
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="tasks", cascade={"persist"})
     * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
     */
    protected $category;
}

class Category
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @ORM\OneToMany(targetEntity="Task", mappedBy="category")
     */
    protected $tasks;
}

Các lớp này nếu bạn chạy lệnh để tạo lược đồ (ví dụ, bin/console doctrine:schema:update --force --dump-sql) , bạn sẽ nhận thấy rằng bảng Category không có cột trên đó cho các tác vụ. (điều này là do nó không có chú thích cột trên đó)

Điều quan trọng cần hiểu ở đây là các nhiệm vụ biến chỉ ở đó vì vậy công cụ học thuyết nội bộ có thể sử dụng tham chiếu phía trên nó cho biết Danh mục ánh xạ của nó. Bây giờ ... đừng nhầm lẫn ở đây như tôi đã ... Category KHÔNG đề cập đến TÊN LỚP , nó đề cập đến thuộc tính trên lớp Tác vụ được gọi là 'protected $ category'.

Giống như khôn ngoan, trên lớp Nhiệm vụ, thuộc tính $ category đề cập đến nó là inversedBy = "task", lưu ý rằng đây là số nhiều, đây KHÔNG phải là SỐ NHIỀU CỦA TÊN LỚP , mà chỉ vì thuộc tính được gọi là 'protected $ task' trong Danh mục lớp học.

Khi bạn hiểu điều này, bạn sẽ rất dễ hiểu những gì inversedBy và mappedBy đang làm và cách sử dụng chúng trong tình huống này.

Bên tham chiếu đến khóa ngoại như 'task' trong ví dụ của tôi luôn nhận thuộc tính inversedBy vì nó cần biết lớp nào (thông qua lệnh targetEntity) và biến nào (inversedBy =) trên lớp đó để 'hoạt động ngược lại' để nói và nhận thông tin danh mục từ. Một cách dễ dàng để nhớ điều này, là lớp sẽ có ngoại khóa_id là lớp cần phải có inversedBy.

Trong trường hợp với category và thuộc tính $ task của nó (không có trong bảng nhớ, chỉ là một phần của lớp cho mục đích tối ưu hóa) là 'task' của MappedBy, điều này tạo ra mối quan hệ chính thức giữa hai thực thể để học thuyết bây giờ có thể an toàn sử dụng câu lệnh SQL JOIN thay vì hai câu lệnh SELECT riêng biệt. Nếu không có mappedBy, công cụ học thuyết sẽ không biết từ câu lệnh JOIN, nó sẽ tạo ra biến nào trong lớp 'Nhiệm vụ' để đưa thông tin danh mục.

Hy vọng điều này giải thích nó tốt hơn một chút.


6
Điều này được giải thích rất tốt và cảm ơn cho nỗ lực của bạn. Tôi đến từ Laravel Eloquent để học thuyết và điều này thật khó đối với tôi để hiểu logic ở đây. Làm tốt. Category is NOT referring TO THE CLASS NAME, its referring to the property on the Task class called 'protected $category'tất cả những gì tôi cần. Nó không chỉ giải quyết vấn đề của tôi mà còn giúp tôi hiểu. Câu trả lời hay nhất IMO :-)
The Alpha

1
Tôi cũng đến từ Eloquent, điều này đã giúp tôi rất nhiều. Điểm gắn bó duy nhất của tôi bây giờ là làm thế nào để thiết lập setter / getter cho việc này, tôi vẫn đang học các sợi dây về nó
Eman

1
Vâng, điều đó thực sự dễ dàng và thậm chí tự động với một số công cụ hiện có, hãy bắt đầu trò chuyện với tôi sau và tôi có thể giúp bạn
Joseph Astrahan

1
Hãy xem câu trả lời này, stackoverflow.com/questions/16629397/…
Joseph Astrahan,

1
symfony.com/doc/current/doctrine/associations.html , thực sự thì tốt hơn nên học, symfony sử dụng học thuyết nên nó sẽ dạy bạn điều tương tự.
Joseph Astrahan

21

Trong mối quan hệ hai chiều có cả mặt sở hữu và mặt nghịch đảo

mappedBy : đưa vào Mặt nghịch đảo của mối quan hệ hai chiều Để tham chiếu đến mặt sở hữu của nó

inversedBy : đưa vào Mặt sở hữu của mối quan hệ hai chiều Để chỉ mặt nghịch đảo của nó

Thuộc tính mappedBy được sử dụng với khai báo ánh xạ OneToOne, OneToMany hoặc ManyToMany.

Thuộc tính inversedBy được sử dụng với khai báo ánh xạ OneToOne, ManyToOne hoặc ManyToMany.

Lưu ý : Bên sở hữu của mối quan hệ hai chiều, bên có chứa khóa ngoại.

có hai tài liệu tham khảo về inversedBy và mappedBy vào Tài liệu Giáo lý: Liên kết thứ nhất , Liên kết thứ hai


1
các liên kết đã chết?
Scaramouche

2

5.9.1. Sở hữu và Mặt nghịch đảo

Đối với các liên kết Nhiều-Nhiều, bạn có thể chọn thực thể nào là bên sở hữu và bên nào là bên nghịch đảo. Có một quy tắc ngữ nghĩa rất đơn giản để quyết định bên nào phù hợp hơn để trở thành bên sở hữu từ góc độ nhà phát triển. Bạn chỉ phải tự hỏi mình, tổ chức nào chịu trách nhiệm quản lý kết nối và chọn đó làm bên sở hữu.

Lấy ví dụ về hai thực thể Article và Tag. Bất cứ khi nào bạn muốn kết nối một Bài viết với một Thẻ và ngược lại, thì điều đó chủ yếu là Bài viết chịu trách nhiệm về mối quan hệ này. Bất cứ khi nào bạn thêm một bài viết mới, bạn muốn kết nối nó với các thẻ hiện có hoặc thẻ mới. Biểu mẫu tạo Bài viết của bạn có thể sẽ hỗ trợ quan điểm này và cho phép chỉ định các thẻ trực tiếp. Đây là lý do tại sao bạn nên chọn Bài viết làm bên sở hữu, vì nó làm cho mã dễ hiểu hơn:

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.