Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine2: field cannot be null when saving entity - due to relationships?

I have an entity called PrintJob, with a ProductId field (amongst others). When I create a new instance of this entity and set all of the fields, then use persist followed by flush, I get an error saying that ProductId cannot be null.

I did a var_dump() on the $productId variable and it comes out as 47. I also did a var_dump() on getProductId() on the new entity (before persist/flush) and the value is still 47.

I think the problem lies with the relationship between the PrintJob entity and the Product entity. Here's the relationship from the PrintJob entity:

/**
 * @OneToOne(targetEntity="Product")
 * @JoinColumn(name="ProductId", referencedColumnName="ProductId")
 */
private $product;

I read somewhere that in the constructor, you need to set the relationship to an empty collection when you're creating new entities (rather than loading existing ones). Here is what I tried doing:

public function __construct()
{
    $this->product = new \Doctrine\Common\Collections\ArrayCollection();
}

However, I get an error:

A new entity was found through a relationship that was not configured to cascade persist operations: Doctrine\Common\Collections\ArrayCollection@000000002cb4568d00000000e92b0fce. Explicitly persist the new entity or configure cascading persist operations on the relationship.

Any help would be much appreciated. The only alternative I've found is to not use relationships :(

I'm using Doctrine 2.0.7.

Additional info:

I'm not creating a new Product entity; the new PrintJob is being linked via the ProductId.

Here's how I am creating the entity - there are a lot of other fields that I can include in the code if it's useful, but I imagine they won't be as the issue is only occurring with ProductId...

    // convert this quote to a print job
    $printJob = new \Dpp\Model\PrintJob;
    $printJob->setProductId($productId);
    // ... other fields ...
    \Dpp\System\Core::getEm()->persist($printJob);
    \Dpp\System\Core::getEm()->flush();

\Dpp\System\Core::getEm() returns the EntityManager.

The mapping part from PrintJob to Product:

/**
 * @OneToOne(targetEntity="Product", cascade={"persist"})
 * @JoinColumn(name="ProductId", referencedColumnName="ProductId")
 */
private $product;

There is no equivalent mapping from Product to PrintJob.

Product entity - columns only:

namespace Dpp\Model;
/**
 * @Entity
 * @Table(name="Brd_Products")
 */
class Product
{
/**
 * @Id @Column(type="integer", name="ProductId")
 * @GeneratedValue
 */
private $productId;

}

Additional info #2:

@JohnM2 pointed out that my associations are not set up correctly. So, here's what I now have.

\Dpp\Model\PrintJob

/**
 * @OneToOne(targetEntity="Product", cascade={"persist"})
 * @JoinColumn(name="ProductId", referencedColumnName="ProductId")
 */
private $product;

/**
 * @return \Dpp\Model\Product
 */
public function getProduct()
{
    return $this->product;
}

/**
 * @param \Dpp\Model\Product $product
 * @return void
 */
public function setProduct($product)
{
    $this->product = $product;
}

\Dpp\Model\Product

/**
 * @Id @Column(type="integer", name="ProductId")
 * @GeneratedValue
 */
private $productId;

public function getProductId()
{
    return $this->productId;
}

The code that saves the new entity:

$productEntity = \Dpp\Query\Product::getById($productId);
$printJob = new \Dpp\Model\PrintJob;
$printJob->setProduct($productEntity);
\Dpp\System\Core::getEm()->persist($printJob);
\Dpp\System\Core::getEm()->flush();

The first line returns an instance of \Dpp\Model\Product. I checked that $productId is set and that $productEntity is populated correctly.

Unfortunately, I now get an error on the "persist" line:

Property productId does not exist

I have a relationship from PrintJob pointing to Product. Do I need one in the opposite direction?

Nearly there though, I hope!

Edit

Never mind, found this last one myself. I needed to set the join column name to productId not ProductId. Fixed. Thank you all :)

like image 369
thirtyish Avatar asked Dec 15 '25 16:12

thirtyish


2 Answers

As far as I understand now, you have PrintJob::$product field and also PrintJob::$productId field. And you are trying to establish a connection between PrintJob and Product using explicit productId "foreign key" field of the PrintJob entity.

But it's not how ORM works. You don't need PrintJob::$productId, Doctrine will create appropriate foreign column from PrintJob::$product field (that what's @JoinColumn annotation says: @JoinColumn(name="ProductId", referencedColumnName="ProductId")). So instead you should establish an association between PrintJob and Product by assigning Product entity (loaded by EntityManager) to PrintJob::$product field by PrintJob->setProduct($product).

like image 93
Dawid Ohia Avatar answered Dec 17 '25 08:12

Dawid Ohia


Try adding cascade={"persist"} to the @OneToOne annotation of $product, like so:

/**
 * @OneToOne(targetEntity="Product", cascade={"persist"})
 * @JoinColumn(name="ProductId", referencedColumnName="ProductId")
 */
private $product;

By default Doctrine doesn't implicitly persists associations to other entities, have a look at this

Also remove this line $this->product = new \Doctrine\Common\Collections\ArrayCollection(); , it doesn't make sense to initialize something that is not a collection as a collection.

Hope it helps

like image 23
jere Avatar answered Dec 17 '25 10:12

jere



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!