【问题标题】:Doctrine2: field cannot be null when saving entity - due to relationships?Doctrine2:保存实体时字段不能为空 - 由于关系?
【发布时间】:2012-01-12 12:12:44
【问题描述】:

我有一个名为 PrintJob 的实体,带有一个 ProductId 字段(以及其他字段)。当我创建此实体的新实例并设置所有字段,然后使用持久化后刷新时,我收到一条错误消息,指出 ProductId 不能为空。

我在$productId 变量上做了一个var_dump(),结果为47。我还在新实体上的getProductId() 上做了一个var_dump()(在持久/刷新之前),值仍然是47。

我认为问题在于PrintJob 实体和Product 实体之间的关系。这是来自PrintJob 实体的关系:

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

我在构造函数中的某处读到,当您创建新实体(而不是加载现有实体)时,您需要将关系设置为空集合。这是我尝试做的:

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

但是,我收到一个错误:

通过未配置为级联持久操作的关系找到一个新实体:Doctrine\Common\Collections\ArrayCollection@000000002cb4568d00000000e92b0fce。显式持久化新实体或在关系上配置级联持久化操作。

任何帮助将不胜感激。我发现的唯一选择是不使用关系:(

我正在使用 Doctrine 2.0.7。

其他信息:

我没有创建新的 Product 实体;新的 PrintJob 正在通过 ProductId 链接。

这是我创建实体的方式 - 如果有用的话,我可以在代码中包含很多其他字段,但我想它们不会是,因为问题只发生在 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() 返回 EntityManager。

PrintJob 到 Product 的映射部分:

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

没有从 Product 到 PrintJob 的等效映射。

产品实体 - 仅列:

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

}

其他信息 #2:

@JohnM2 指出我的关联设置不正确。所以,这就是我现在拥有的。

\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\型号\产品

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

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

保存新实体的代码:

$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();

第一行返回\Dpp\Model\Product 的一个实例。我检查了 $productId 是否已设置,并且 $productEntity 已正确填充。

不幸的是,我现在在“persist”行出现错误:

Property productId does not exist

我有一个从 PrintJob 指向 Product 的关系。我需要一个反方向的吗?

我希望快到了!

编辑

没关系,我自己找到了最后一个。我需要将连接列名称设置为 productId 而不是 ProductId。固定的。谢谢大家:)

【问题讨论】:

  • “我收到一条错误消息,说 ProductId 不能为空” 你从哪里得到这个错误?如果您不这样做,那么@jere 建议的 cascade={"persist"} 就是您的答案。
  • 在创建实体,设置字段值,然后使用持久化后刷新后发生该错误。当我冲洗时发生错误。实体未保存。
  • 如果您编辑您的问题并显示创建实体、设置字段值和刷新的代码,这将有所帮助。并且还显示产品实体定义(只有字段,没有方法)。
  • 您是否正在创建两个实体的新实例?意思是,你是在创建一个新的PrintJob,然后是一个新的Product,并将Product 设置为新创建的PrintJob?也许您可以发布实体的映射以及用于创建实体的代码
  • 添加了更多信息。谢谢。

标签: php doctrine-orm


【解决方案1】:

据我所知,您有PrintJob::$product 字段和PrintJob::$productId 字段。 您正在尝试使用PrintJob 实体的显式productId“外键”字段在PrintJobProduct 之间建立连接。

但这不是 ORM 的工作方式。您不需要PrintJob::$productId,Doctrine 将从PrintJob::$product 字段创建适当的外部列(@JoinColumn 注释说:@JoinColumn(name="ProductId", referencedColumnName="ProductId"))。因此,您应该通过将 Product 实体(由 EntityManager 加载)分配给 PrintJob::$product 字段由 PrintJob->setProduct($product) 来建立 PrintJob 和 Product 之间的关联。

【讨论】:

  • 谢谢 - 这解释了很多!所以现在当我保存实体时,我使用的是 setProduct 而不是 setProductId,当我尝试保留实体时,我收到一个错误:“属性 productId 不存在”。我将使用修改后的代码更新原始信息...
【解决方案2】:

尝试将cascade={"persist"} 添加到$product@OneToOne 注释中,如下所示:

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

默认情况下,Doctrine 不会隐式保留与其他实体的关联,请查看 this

同样去掉这行$this->product = new \Doctrine\Common\Collections\ArrayCollection(); ,把不是集合的东西初始化为集合是没有意义的。

希望对你有帮助

【讨论】:

  • Doctrine 关于这个主题的文档doctrine-project.org/docs/orm/2.1/en/reference/… 要记住的重要一点是:“这个概念被称为 Persistence by Reachability:只要关联是,在已托管实体上找到的新实体就会自动持久化定义为级联持久化。”
  • 谢谢,我已经进行了必要的更改,但是在尝试刷新以保存新实体时,我仍然收到“ProductId 不能为空”错误。我正在使用 Doctrine 2.0.7 - 将其添加到问题中。我是否需要添加另一个方向的关系,即从 Product 到 PrintJob?
猜你喜欢
  • 1970-01-01
  • 2011-12-29
  • 2018-03-16
  • 1970-01-01
  • 2011-11-13
  • 1970-01-01
  • 2019-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多