user2559108
user2559108

Reputation:

Issue with ManyToMany relationship

I have 2 enteties.

A package, and a StockItem.

The Package can have many StockItems, and the StockItem can belong to Many packages. A ManyToMany seems most appropriate.

The issue appears when i attempt to add 2 of the same stockitems to a package, we get an Integraty violation:

{"code":500,"message":"An exception occurred while executing 'INSERT INTO StockItem_In_Package (package_id, stockitem_id) VALUES (?, ?)' with params [4, 1]:\n\nSQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '4-1' for key 'PRIMARY'"}

Since Package(id 4), creates 2 relationships with stockItem 1.

4-1 and 4-1

Is it possible to get around this in any way? Is it possible to add a third column named id to the ManyToMany table, or add one named ItemCountInPackage, and just increment that by one when the same is added to a package? What would be the best solution.

Package Entity, only inserting relevant code:

/**
 * Package
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="IHEnterprise\LogisticsBundle\Entity\PackageRepository")
 * @ORM\HasLifecycleCallbacks
 *
 * @ExclusionPolicy("all")
 *
 */
class Package
{

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

    /**
     * @ORM\ManyToMany(targetEntity="IHEnterprise\LogisticsBundle\Entity\StockItem", cascade={"all"}, indexBy="package_id")
     * @ORM\JoinTable(name="StockItem_In_Package",
     *      joinColumns={@ORM\JoinColumn(name="package_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="stockitem_id", referencedColumnName="id")}
     *      )
     * @Expose
     * @Assert\NotNull()
     **/
    private $stockItems;
}

StockItem Entity, only inserting relevant code:

/**
 * StockItem
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="IHEnterprise\LogisticsBundle\Entity\StockItemRepository")
 * @ORM\HasLifecycleCallbacks
 *
 * @ExclusionPolicy("all")
 *
 */
class StockItem
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @Expose
     */
    private $id;
}

I do not need to keep track of what StockItems belong to which packages, only what packages contain which stockitems.

Upvotes: 1

Views: 59

Answers (2)

RSez
RSez

Reputation: 271

You can't add a third column to your ManyToMany relationship. So you can't have the same StockItem twice in one package.

To have more than one piece of the same StockItem in one package, you have to create a third entity with an unique id, and a ManyToOne relationship to StockItem and Package (and a OneToMany relationship in StockItem & Package to your third entity).

Upvotes: 1

Michael Villeneuve
Michael Villeneuve

Reputation: 4033

It looks like you are trying to insert an item that was already in the database as a new record. To prevent such an error do the following :

/**
 * @desc Add only new items to a single package 
 * @param \AcmeBundle\Entity\Package $package
 * @param ArrayCollection<StockItem> $stockItems
 */
public function addStockItemsAction(Package $package, $stockItems) {
    foreach ($stockItems as $stockItem) {
        if ($package->contains($stockItem) === false) {
            $package->addStockItem($stockItem);
        }
    }    
}

Upvotes: 0

Related Questions