Doctrine 2 ORM 中的一对多关系不插入远程密钥
Stack Overflow 会员大家好!
我对某些第 2 条关系有疑问,这些关系目前让我陷入困境。
我正在尝试在 Doctrine 中在我的 AnalyticsCampaign 模型和我的 AnalyticsData 模型之间建立一个非常好且简单的一对多关系。
下面是我的代码和我的问题。
foreach($entries as $entry)
{
// Instance of AnalyticsCampaign model with data in it.
$campaign = $this->_getCampaignByGoogleId($entry['campaignId']);
$daysAgo = time() - $campaign->getUpdated();
$dateCreated = time() - $campaign->getCreated();
if($daysAgo>=86400 || $dateCreated < 86400)
{
// More or equal to 1 day has passed since last database update
// Let's insert these fuckers.
// Insert the new GA data.
$data = new Model_AnalyticsData();
$data->fromArray($entry);
$data->setCampaign($campaign->getId());
$campaign->data = array($data);
$this->em->persist($campaign);
}
}
$this->em->flush();
分析活动数据
<?php
/**
* AnalyticsCampaign
*
* @Table(name="analyticsCampaign")
* @Entity
*/
class Model_AnalyticsCampaign
{
const STATUS_ACTIVE = 1;
const STATUS_INACTIVE = 0;
/**
* @var integer $id
*
* @Column(name="id", type="integer", nullable=false)
* @Id
* @GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var string $name
*
* @Column(name="name", type="string", length=255, nullable=true)
*/
private $name;
/**
* @var string $analyticsCampaignId
*
* @Column(name="analyticsCampaignId", type="integer", length=25, nullable=false)
*/
private $analyticsCampaignId;
/**
* @Column(type="integer")
*/
private $updated;
/**
* @Column(type="integer")
*/
private $created;
/**
* @Column(type="integer")
*/
private $status;
/**
* @OneToMany(targetEntity="Model_AnalyticsData", mappedBy="campaign", cascade={"persist"})
* @param \Doctrine\Common\Collections\ArrayCollection $data
*/
private $data;
public function __construct()
{
$this->updated();
$this->created = time();
if(empty($this->status))
{
$this->status = Model_AnalyticsCampaign::STATUS_INACTIVE;
}
}
public function updated()
{
$this->updated = time();
}
public function created()
{
$this->created = time();
}
public function getId()
{
return $this->id;
}
public function fromArray(array $array)
{
$objects = get_object_vars($this);
foreach($array as $item => $value)
{
if(array_key_exists($item, $objects))
{
$this->$item = $value;
}
}
}
public function setUpdated()
{
$this->updated();
}
public function getUpdated()
{
return ((!empty($this->updated)) ? $this->updated : 0);
}
public function setCreated()
{
$this->created();
}
public function getCreated()
{
return ((!empty($this->created)) ? $this->created : 0);
}
public function setStatus($status)
{
$statusFlag = "SELF::STATUS_".strtoupper($status);
if(!defined($statusFlag))
{
throw new \InvalidArgumentException("Status '$status' is not valid", 500);
}
$this->status = constant($statusFlag);
}
public function getStatus()
{
$constants = getActiveStatusConstants();
if(isset($constants[$this->status]))
{
return $constants[$this->status];
}
}
private function getActiveStatusConstants()
{
$vars = get_object_vars();
$potentialStatus = array();
foreach($vars as $var)
{
if(strpos("STATUS_") == 0)
{
// Matching all of our status variables.
$potentialStatus[] = array(
constant("SELF::$var") => substr($var, 7, strlen($var))
);
}
}
return $potentialStatus;
}
public function __get($property)
{
return $this->$property;
}
public function __set($property,$value)
{
$this->$property = $value;
}
}
AnalyticsData 模型
<?php
/**
* AnalyticsData
*
* @Table(name="analyticsData")
* @Entity
*/
class Model_AnalyticsData
{
public function __construct()
{
// constructor is never called by Doctrine
$this->created = $this->updated = time();
}
/**
* @var integer $id
*
* @Column(name="id", type="integer", nullable=false)
* @Id
* @GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var integer $campaignrank
*
* @Column(name="campaignRank", type="integer", nullable=true)
*/
private $campaignRank;
/**
* @var decimal $cost
*
* @Column(name="cost", type="decimal", nullable=true)
*/
private $cost;
/**
* @var integer $impressions
*
* @Column(name="impressions", type="integer", nullable=true)
*/
private $impressions;
/**
* @var integer $clicks
*
* @Column(name="clicks", type="integer", nullable=true)
*/
private $clicks;
/**
* @var decimal $costperclick
*
* @Column(name="costPerClick", type="decimal", nullable=true)
*/
private $costPerClick;
/**
* @var integer $averagecampaignposition
*
* @Column(name="averageCampaignPosition", type="integer", nullable=true)
*/
private $averageCampaignPosition;
/**
* @Column(type="integer")
*/
private $created;
/**
* @Column(type="integer")
*/
private $updated;
/**
*
* Store a reference to the campaign that this relates to
* @ManyToOne(targetEntity="Model_AnalyticsCampaign", inversedBy="data")
* @JoinColumn(name="campaignId", referencedColumnName="id")
*/
protected $campaign;
public function fromArray(array $array)
{
$objects = get_object_vars($this);
foreach($array as $item => $value)
{
if(array_key_exists($item, $objects))
{
$this->$item = $value;
}
}
}
/**
* @PreUpdate
*/
public function updated()
{
$this->updated = time();
}
public function setCampaign($id)
{
$this->campaign = $id;
}
}
我遇到的问题是,它实际上毫无问题地添加了子表数据,但它没有填充 AnalyticsData 内部的 CampaignId 字段。
当我手动尝试设置该 ID 而不是它这样做时,它会向我显示:
Exception information:
Message: A new entity was found through a relationship that was not configured to cascade persist operations: @. Explicitly persist the new entity or configure cascading persist operations on the relationship.
Stack trace:
#0 /usr/share/php/Doctrine/ORM/UnitOfWork.php(490): Doctrine\ORM\UnitOfWork->computeAssociationChanges(Array, 1)
#1 /usr/share/php/Doctrine/ORM/UnitOfWork.php(505): Doctrine\ORM\UnitOfWork->computeChangeSet(Object(Doctrine\ORM\Mapping\ClassMetadata), Object(Model_AnalyticsData))
#2 /usr/share/php/Doctrine/ORM/UnitOfWork.php(249): Doctrine\ORM\UnitOfWork->computeChangeSets()
#3 /usr/share/php/Doctrine/ORM/EntityManager.php(328): Doctrine\ORM\UnitOfWork->commit()
#4 /home/tom/development/seo.qe.org/application/modules/default/controllers/AnalyticsController.php(64): Doctrine\ORM\EntityManager->flush()
#5 /usr/share/php/Zend/Controller/Action.php(513): AnalyticsController->indexAction()
#6 /usr/share/php/Zend/Controller/Dispatcher/Standard.php(295): Zend_Controller_Action->dispatch('indexAction')
#7 /usr/share/php/Zend/Controller/Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
#8 /usr/share/php/Zend/Application/Bootstrap/Bootstrap.php(97): Zend_Controller_Front->dispatch()
#9 /usr/share/php/Zend/Application.php(366): Zend_Application_Bootstrap_Bootstrap->run()
#10 /home/tom/development/seo.qe.org/public/index.php(26): Zend_Application->run()
#11 {main}
Request Parameters:
array (
'controller' => 'analytics',
'action' => 'index',
'module' => 'default',
)
以前有人见过这个吗?如果是的话,我到底做错了什么?
非常感谢,我会给1,000,000个互联网给可以帮助的人!
Hi there Stack Overflow members!
I am having a problem with some Doctrine 2 relations that are current running me into the ground.
I am attempting to setup a very nice and simple One to Many relationship in Doctrine between my AnalyticsCampaign model and my AnalyticsData model.
Below is my code and my problem.
foreach($entries as $entry)
{
// Instance of AnalyticsCampaign model with data in it.
$campaign = $this->_getCampaignByGoogleId($entry['campaignId']);
$daysAgo = time() - $campaign->getUpdated();
$dateCreated = time() - $campaign->getCreated();
if($daysAgo>=86400 || $dateCreated < 86400)
{
// More or equal to 1 day has passed since last database update
// Let's insert these fuckers.
// Insert the new GA data.
$data = new Model_AnalyticsData();
$data->fromArray($entry);
$data->setCampaign($campaign->getId());
$campaign->data = array($data);
$this->em->persist($campaign);
}
}
$this->em->flush();
Analytics Campaign data
<?php
/**
* AnalyticsCampaign
*
* @Table(name="analyticsCampaign")
* @Entity
*/
class Model_AnalyticsCampaign
{
const STATUS_ACTIVE = 1;
const STATUS_INACTIVE = 0;
/**
* @var integer $id
*
* @Column(name="id", type="integer", nullable=false)
* @Id
* @GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var string $name
*
* @Column(name="name", type="string", length=255, nullable=true)
*/
private $name;
/**
* @var string $analyticsCampaignId
*
* @Column(name="analyticsCampaignId", type="integer", length=25, nullable=false)
*/
private $analyticsCampaignId;
/**
* @Column(type="integer")
*/
private $updated;
/**
* @Column(type="integer")
*/
private $created;
/**
* @Column(type="integer")
*/
private $status;
/**
* @OneToMany(targetEntity="Model_AnalyticsData", mappedBy="campaign", cascade={"persist"})
* @param \Doctrine\Common\Collections\ArrayCollection $data
*/
private $data;
public function __construct()
{
$this->updated();
$this->created = time();
if(empty($this->status))
{
$this->status = Model_AnalyticsCampaign::STATUS_INACTIVE;
}
}
public function updated()
{
$this->updated = time();
}
public function created()
{
$this->created = time();
}
public function getId()
{
return $this->id;
}
public function fromArray(array $array)
{
$objects = get_object_vars($this);
foreach($array as $item => $value)
{
if(array_key_exists($item, $objects))
{
$this->$item = $value;
}
}
}
public function setUpdated()
{
$this->updated();
}
public function getUpdated()
{
return ((!empty($this->updated)) ? $this->updated : 0);
}
public function setCreated()
{
$this->created();
}
public function getCreated()
{
return ((!empty($this->created)) ? $this->created : 0);
}
public function setStatus($status)
{
$statusFlag = "SELF::STATUS_".strtoupper($status);
if(!defined($statusFlag))
{
throw new \InvalidArgumentException("Status '$status' is not valid", 500);
}
$this->status = constant($statusFlag);
}
public function getStatus()
{
$constants = getActiveStatusConstants();
if(isset($constants[$this->status]))
{
return $constants[$this->status];
}
}
private function getActiveStatusConstants()
{
$vars = get_object_vars();
$potentialStatus = array();
foreach($vars as $var)
{
if(strpos("STATUS_") == 0)
{
// Matching all of our status variables.
$potentialStatus[] = array(
constant("SELF::$var") => substr($var, 7, strlen($var))
);
}
}
return $potentialStatus;
}
public function __get($property)
{
return $this->$property;
}
public function __set($property,$value)
{
$this->$property = $value;
}
}
AnalyticsData Model
<?php
/**
* AnalyticsData
*
* @Table(name="analyticsData")
* @Entity
*/
class Model_AnalyticsData
{
public function __construct()
{
// constructor is never called by Doctrine
$this->created = $this->updated = time();
}
/**
* @var integer $id
*
* @Column(name="id", type="integer", nullable=false)
* @Id
* @GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var integer $campaignrank
*
* @Column(name="campaignRank", type="integer", nullable=true)
*/
private $campaignRank;
/**
* @var decimal $cost
*
* @Column(name="cost", type="decimal", nullable=true)
*/
private $cost;
/**
* @var integer $impressions
*
* @Column(name="impressions", type="integer", nullable=true)
*/
private $impressions;
/**
* @var integer $clicks
*
* @Column(name="clicks", type="integer", nullable=true)
*/
private $clicks;
/**
* @var decimal $costperclick
*
* @Column(name="costPerClick", type="decimal", nullable=true)
*/
private $costPerClick;
/**
* @var integer $averagecampaignposition
*
* @Column(name="averageCampaignPosition", type="integer", nullable=true)
*/
private $averageCampaignPosition;
/**
* @Column(type="integer")
*/
private $created;
/**
* @Column(type="integer")
*/
private $updated;
/**
*
* Store a reference to the campaign that this relates to
* @ManyToOne(targetEntity="Model_AnalyticsCampaign", inversedBy="data")
* @JoinColumn(name="campaignId", referencedColumnName="id")
*/
protected $campaign;
public function fromArray(array $array)
{
$objects = get_object_vars($this);
foreach($array as $item => $value)
{
if(array_key_exists($item, $objects))
{
$this->$item = $value;
}
}
}
/**
* @PreUpdate
*/
public function updated()
{
$this->updated = time();
}
public function setCampaign($id)
{
$this->campaign = $id;
}
}
The problem I am having is that it does actually add the child table data without an issue, however it dosen't fill in my campaignId field that's inside AnalyticsData.
When I manually try and set that ID rather than it doing it then it presents me with:
Exception information:
Message: A new entity was found through a relationship that was not configured to cascade persist operations: @. Explicitly persist the new entity or configure cascading persist operations on the relationship.
Stack trace:
#0 /usr/share/php/Doctrine/ORM/UnitOfWork.php(490): Doctrine\ORM\UnitOfWork->computeAssociationChanges(Array, 1)
#1 /usr/share/php/Doctrine/ORM/UnitOfWork.php(505): Doctrine\ORM\UnitOfWork->computeChangeSet(Object(Doctrine\ORM\Mapping\ClassMetadata), Object(Model_AnalyticsData))
#2 /usr/share/php/Doctrine/ORM/UnitOfWork.php(249): Doctrine\ORM\UnitOfWork->computeChangeSets()
#3 /usr/share/php/Doctrine/ORM/EntityManager.php(328): Doctrine\ORM\UnitOfWork->commit()
#4 /home/tom/development/seo.qe.org/application/modules/default/controllers/AnalyticsController.php(64): Doctrine\ORM\EntityManager->flush()
#5 /usr/share/php/Zend/Controller/Action.php(513): AnalyticsController->indexAction()
#6 /usr/share/php/Zend/Controller/Dispatcher/Standard.php(295): Zend_Controller_Action->dispatch('indexAction')
#7 /usr/share/php/Zend/Controller/Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
#8 /usr/share/php/Zend/Application/Bootstrap/Bootstrap.php(97): Zend_Controller_Front->dispatch()
#9 /usr/share/php/Zend/Application.php(366): Zend_Application_Bootstrap_Bootstrap->run()
#10 /home/tom/development/seo.qe.org/public/index.php(26): Zend_Application->run()
#11 {main}
Request Parameters:
array (
'controller' => 'analytics',
'action' => 'index',
'module' => 'default',
)
Has anyone seen this before, if so, what on earth am I doing wrong??
Thanks very much, I will give 1,000,000 internets to the person that can help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题是因为我需要将 AnalyticsData 插入 AnalyticsCampaign,然后将 AnaltyicsCampaign 插入 AnalyticsData。
我对教义的思考显然是完全错误的。我需要从对象的角度来思考它。因此,当我尝试插入 CampaignId 时,它失败了,因为 Doctrine 必须与对象而不是 ID 建立关系。
所以我的代码最终是这样的:
因为 $campaign->data 是一个 ArrayObject,它不会只接受该对象,所以你需要先将它放入一个数组中(显然意味着你可以插入尽可能多的子实体)你想要的)。
就是这样!
所有功劳都归功于 Freenode IRC 上 #doctrine 上的 Beberlei。
The problem was because I needed to insert the AnalyticsData into AnalyticsCampaign and then AnaltyicsCampaign into AnalyticsData.
I was thinking about Doctrine apparently entirely the wrong way. I needed to think about it in terms of objects. So when I was trying to insert the CampaignId it was failing because Doctrine has to establish relationships with Objects rather than ID's.
So my code ended up as this:
So because $campaign->data is an ArrayObject, it won't accept just the object, so you need to put it in an Array first (obviously meaning you could insert as many child entities as you wanted).
So that was it!
All credit goes to Beberlei on #doctrine on freenode IRC.