【问题标题】:Doctrine : many-to-many with extra columns in reference table教义:多对多,参考表中有额外的列
【发布时间】:2017-01-26 09:31:45
【问题描述】:

我对 Symfony3/doctrine2 和多对多的额外列有疑问。我刚开始用它开发

是的,我看到了帖子:Doctrine2: Best way to handle many-to-many with extra columns in reference table 但老实说,我不明白为什么它不适用于我的代码......

我被困两天了,在谷歌上看(他不是我的朋友),阅读文档......我的大脑不明白......

请帮我理解为什么。

问题

我有成员和地址实体。我想按成员的所有地址或按地址的所有成员。所以,多对多在 Doctrine 中。 在我的加入表上,我需要有一个额外的列favorite_address 所以,我需要有 3 个实体:Member、Address、MemberAddress

实体成员:

class Member implements AdvancedUserInterface
{

....

/**
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\Member\MemberAddress", mappedBy="member", cascade={"all"})
 * @ORM\JoinTable(name="member_address",
 *      joinColumns={@ORM\JoinColumn(name="member_id", referencedColumnName="id")})
 */
private $addresses;

....

public function __construct(){
    $this->addresses = new ArrayCollection();
}

/**
 * Add an address
 * @param Address $address
 */
public function addAddress(\AppBundle\Entity\Address\Address $address)
{
    // Ici, on utilise l'ArrayCollection vraiment comme un tableau
    $this->addresses[] = $address;
}

/**
 * Remove an address
 * @param Address $address
 */
public function removeAddress(\AppBundle\Entity\Address\Address $address)
{
    // Ici on utilise une méthode de l'ArrayCollection, pour supprimer la catégorie en argument
    $this->addresses->removeElement($address);
}

/**
 * Get all addresses
 * @return ArrayCollection
 */
public function getAddresses()
{
    return $this->addresses;
}

实体地址:

class Address
{
....

/**
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\Member\MemberAddress", mappedBy="address", cascade={"all"})
 * @ORM\JoinTable(name="member_address",
 *      joinColumns={@ORM\JoinColumn(name="address_id", referencedColumnName="id")})
 */
private $members;

....

/**
 * Add a member
 * @param Member $member
 */
public function addMember(\AppBundle\Entity\Member\Member $member)
{
    // Ici, on utilise l'ArrayCollection vraiment comme un tableau
    $this->members[] = $member;
}

/**
 * Remove a member
 * @param Member $member
 */
public function removeMember(\AppBundle\Entity\Member\Member $member)
{
    // Ici on utilise une méthode de l'ArrayCollection, pour supprimer la catégorie en argument
    $this->members->removeElement($member);
}

/**
 * Get all members
 * @return ArrayCollection
 */
public function getMembers()
{
    return $this->members;
}

最后一个实体:MemberAddressReference

class MemberAddress
{
/**
 * @ORM\Id
 * @ORM\Column(type="integer")
 * @ORM\GeneratedValue(strategy="AUTO")
 */
protected $id;

/** @ORM\ManyToOne(targetEntity="AppBundle\Entity\Member\Member", inversedBy="addresses")
 *  @ORM\JoinColumn(name="member_id", referencedColumnName="id")
 */
protected $member;

/** @ORM\ManyToOne(targetEntity="AppBundle\Entity\Address\Address", inversedBy="members")
 *  @ORM\JoinColumn(name="address_id", referencedColumnName="id")
 */
protected $address;

/** @ORM\Column(type="boolean") */
protected $isFavorite;

最后,控制器

class MemberAddressController extends Controller
{

public function createAction(Request $request){
    ....
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $currentDate = new \DateTime("now");

        $em = $this->getDoctrine()->getManager();
        $address = new Address();
        $memberAddress = new MemberAddress();

        $address->setType($form['type']->getData());
        $address->setCreated($currentDate);
        $address->setModified($currentDate);

        $memberAddress->setMember($member);
        $memberAddress->setAddress($address);
        $memberAddress->setFavorite(1);

        $em->persist($member);
        $em->persist($address);
        $em->persist($memberAddress);

        $member->addAddress($address);

        $em->flush();

        dump($member);
        die();
    }

那么,怎么了

我收到此错误:

Expected value of type "Doctrine\Common\Collections\Collection|array" for association field "AppBundle\Entity\Member\Member#$addresses", got "AppBundle\Entity\Address\Address" instead.

是的,类型不好,我明白,但为什么他不好?

public function addAddress(\AppBundle\Entity\Address\Address $address)
{
    // Ici, on utilise l'ArrayCollection vraiment comme un tableau
    $this->addresses[] = $address;
}

addAddress 获取地址对象,不是吗?那么他为什么要等一个数组呢?

请帮帮我,我快疯了……

【问题讨论】:

  • @JoinTable 注释不正确,应删除。它仅适用于没有额外属性的最简单的多对多关系。
  • 好的,谢谢。我删除了它。但保存时仍然出错。

标签: symfony doctrine-orm


【解决方案1】:

我不明白您的 memberAdress 实体的目标。如果要创建 OneToMany 双向关系,则不需要创建第三个实体。 根据学说文档:

   /** @Entity */
class Product
{
    // ...
    /**
     * One Product has Many Features.
     * @OneToMany(targetEntity="Feature", mappedBy="product")
     */
    private $features;
    // ...

    public function __construct() {
        $this->features = new ArrayCollection();
    }
}

/** @Entity */
class Feature
{
    // ...
    /**
     * Many Features have One Product.
     * @ManyToOne(targetEntity="Product", inversedBy="features")
     * @JoinColumn(name="product_id", referencedColumnName="id")
     */
    private $product;
    // ...
}

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

编辑

如果您想使用第三方实体,您的地址和您的成员之间没有关系。它们只是由第三方链接。 所以你应该这样映射:

会员实体:

class Member implements AdvancedUserInterface
{
/**
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\Member\MemberAddress", mappedBy="member", cascade={"all"})
 */
private $addresses;

地址实体

class Address
{
/**
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\Member\MemberAddress", mappedBy="address", cascade={"all"})
 */
private $members;

如果您想要成员的所有地址,则需要创建一个自定义存储库以将您的地址表与其他两个表连接起来。

【讨论】:

  • 因为 1 个地址可以有 N 个成员,而不仅仅是 1 个成员。 (如果我想要在此地址工作的成员列表),那么,我需要使用 ManyToMany,不是吗?这不正确吗?而且,如果我需要为喜欢的地址添加额外的列,我需要第三个实体,不是吗?
  • 好的,所以使用多对多关系作为我提供的文档链接解释。您不需要第三个实体,学说会自己创建一个 joinTable 并管理关系。
  • doctrine 将创建一个带有 ManyToMany 的 joinTable,当然,我同意你的观点,但如果我需要向其中添加额外的 Column,则不会。我需要知道我的成员和他们的地址之间最喜欢的地址。因此,我在 Google 和此处 [link]stackoverflow.com/questions/3542243/… 上看到,我需要第三个实体来添加额外的列。还有其他方法可以做我想做的事吗?
  • 好的,对不起,我没听懂你的问题。但是您是否使用第三个实体,链接到具有 oneToMany 关系的其他两个实体。您不需要像在成员实体中为地址属性使用的连接表......我认为问题出在这里
  • 对不起,如果一开始不清楚。 “但是您是否使用第三个实体,链接到具有 oneToMany 关系的其他两个实体”。 是的,它是 memberAddress。 “您不需要像在成员实体中用于地址属性的连接表......我认为问题出在此处” 抱歉,我不明白。那么,我怎样才能让所有成员的所有地址或所有成员的地址?
猜你喜欢
  • 2013-02-03
  • 1970-01-01
  • 2018-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多