Php Doctrine2批量导入尝试使用其他实体
我正在为一个大型项目处理Php Doctrine2批量导入尝试使用其他实体,php,doctrine-orm,zend-framework2,Php,Doctrine Orm,Zend Framework2,我正在为一个大型项目处理成员导入批处理(带有插入和更新),该项目有许多实体,例如成员,客户端,组,… 在阅读了doc中有关批量进口的章节后,我实现了以下代码: $batchSize = 20; $i = 0; foreach ($entities as $entity) { $this->getEntityManager()->persist($entity); if (($i % $batchSize) === 0) {
成员
导入批处理(带有插入和更新),该项目有许多实体,例如成员
,客户端
,组
,…
在阅读了doc中有关批量进口的章节后,我实现了以下代码:
$batchSize = 20;
$i = 0;
foreach ($entities as $entity)
{
$this->getEntityManager()->persist($entity);
if (($i % $batchSize) === 0)
{
$this->getEntityManager()->flush();
$this->getEntityManager()->clear();
}
}
$this->getEntityManager()->flush();
$this->getEntityManager()->clear();
现在,当我想批量处理成员
实体数组时,我会尝试将空数据插入到与组
实体相关的完全其他表中,并引发异常执行“插入组…”时发生异常
成员
和组
之间没有任何关系
你知道这种奇怪的行为吗
编辑
简短的映射详细信息:
/**
* @ORM\Entity
* @ORM\Table(name="members")
*/
class Member
{
// some properties ...
/**
* @ORM\ManyToOne(targetEntity="Client", inversedBy="members", cascade={"persist", "merge"})
* @ORM\JoinColumn(name="client_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $client;
/**
* @return Client
*/
public function getClient()
{
return $this->client;
}
/**
* @param Client $client
*
* @return $this
*/
public function setClient(Client $client)
{
$this->client = $client;
return $this;
}
}
/**
* @ORM\Entity
* @ORM\Table(name="clients")
*/
class Client
{
/**
* @ORM\OneToMany(targetEntity="Member", mappedBy="client", cascade={"persist", "remove", "merge"}, fetch="EXTRA_LAZY")
*/
protected $members;
/**
* @ORM\ManyToOne(targetEntity="Group", inversedBy="clients", cascade={"persist", "merge"})
* @ORM\JoinColumn(name="clients_id", referencedColumnName="id", onDelete="SET NULL")
*/
protected $group;
public function __construct()
{
$this->members = new ArrayCollection();
}
/**
* @return ArrayCollection
*/
public function getMembers()
{
return $this->members;
}
/**
* @param $members
*
* @return $this
*/
public function setMembers($members)
{
$this->members = new ArrayCollection();
return $this->addMembers($members);
}
/**
* @param $members
*
* @return $this
*/
public function addMembers($members)
{
foreach ($members as $member)
{
$this->addMember($member);
}
return $this;
}
/**
* @param Member $member
*
* @return $this
*/
public function addMember(Member $member)
{
$this->members->add($member);
$member->setClient($this);
return $this;
}
/**
* @param Member $member
*
* @return $this
*/
public function removeMember(Member $member)
{
if ($this->members->contains($member))
{
$this->members->removeElement($member);
}
return $this;
}
/**
* @param $members
*
* @return $this
*/
public function removeMembers($members)
{
foreach ($members as $member)
{
$this->removeMember($member);
}
return $this;
}
/**
* @param Group $group
*
* @return $this
*/
public function setGroup(Group $group = null)
{
$this->group = $group;
return $this;
}
/**
* @return Group
*/
public function getGroup()
{
return $this->group;
}
}
/**
* @ORM\Entity
* @ORM\Table(name="groups")
*/
class Group
{
/**
* @ORM\OneToMany(targetEntity="Client", mappedBy="group")
*/
protected $clients;
public function __construct()
{
$this->clients = new ArrayCollection();
}
/**
* @return ArrayCollection
*/
public function getClients()
{
return $this->clients;
}
/**
* @param $clients
*
* @return $this
*/
public function setClients($clients)
{
$this->clients = new ArrayCollection();
return $this->addClients($clients);
}
/**
* @param $clients
*
* @return $this
*/
public function addClients($clients)
{
foreach ($clients as $client)
{
$this->addClient($client);
}
return $this;
}
/**
* @param Client $client
*
* @return $this
*/
public function addClient(Client $client)
{
if (!$this->clients->contains($client))
{
$this->clients->add($client);
$client->setGroup($this);
}
return $this;
}
/**
* @param $clients
*
* @return $this
*/
public function removeClients($clients)
{
foreach ($clients as $client)
{
$this->removeClient($client);
}
return $this;
}
/**
* @param Client $client
*
* @return $this
*/
public function removeClient(Client $client)
{
if ($this->clients->contains($client))
{
$this->clients->removeElement($client);
$client->setGroup(null);
}
return $this;
}
}
错误类型为:
执行“插入到组中”时发生异常。。。SQLSTATE[23502]:非空冲突:7错误:“标签”列中的空值违反非空约束
详细信息:失败的行包含(60,null,f,null,f,null,null)。
编辑2
这是表创建说明(使用postgresql):
我可以描述导致错误的原因,但只能猜测错误的原因,并给出一些调试该错误时要查找的提示
正如您所描述的,您正在更新成员,这些成员是客户端的一部分,而客户端又是组的一部分。正如您在关系中通过cascade=persist
指定的那样,在持久化成员时,客户机和组也会被保存。这意味着,在插入成员时会更新或创建组。在您的情况下,您正在通过此机制创建一个新组。但是,该组没有标签
属性集,导致数据库中出现NULL
值,这是方案不允许的
正如您所说,这个错误已经在最佳批次中发生。您更新隐式的前20个成员之一创建了一个没有标签的新组。为了找出它是哪一个,我建议在持久化之前使用调试器并检查每个成员,以查看该成员的组是什么,以及它是否存在于数据库中。如果它不存在(通过ID
),则应调查此组未设置所需标签的原因
如果数据库中确实已经存在所有组,事情会变得更加棘手,这取决于您正在更新的成员的加载方式。它们是从EntityManager(managed
状态)获取的,还是从其他源(例如序列化的
)加载的,因此处于非托管的
状态?如果它们是非托管的,则它们将在到期时变为托管,并且通过指定关系cascade=merge
,客户机和组也将变为托管。不过,这里有一件重要的事情需要知道,merge
将返回一个新的(托管)实体,然后该实体将被持久化(请参阅)。由于这是一个新对象,因此该对象可能没有完全初始化,并且可能包含未定义的值(然后将转换为NULL
)。
因此,当从不同于EntityManager的源加载成员
数据时,您可能必须首先将其与EntityManager连接以避免此问题
调试最后一个是相当困难的,您需要进入UnitOfWork->doPersist
方法来查看每个实体是如何实际持久化的。您有没有可能将这两个类的映射细节添加到问题中?您是否尝试过使用调试器单步执行此循环,并查看此异常是否已在第一次循环迭代中发生,还是仅在以后的迭代中发生?嗨,Fge,很抱歉我的回答太晚了。。。请检查我的编辑以获取有关此问题的更多详细信息。感谢您的时间,我使用了一个调试器,但是在FlushGroups上第一次插入时出现了错误。组实体似乎与数据库表结构不一致?是否删除了任何映射?如果没有,您是否也可以添加SHOW CREATE TABLE groups
的输出?另请注意,您没有在Client
entity:)@Fge中将groups
初始化为ArrayCollection
,谢谢您的明确回答。此错误出现在第一次插入/更新时。May cascade={“persist”,“merge”}在多通客户端::$group
和成员::$Client
上是此行为的原因。批量保存方法实际上与“普通”保存方法相同。唯一的区别是EntityManager
清除。我会这样调查的+这是一个很好的答案
CREATE TABLE groups (
id integer NOT NULL,
tempref character varying(255) DEFAULT NULL::character varying,
prorated_basis boolean NOT NULL,
fixed_price_amount double precision,
is_indexed boolean,
pricing_grid pricing[],
label character varying(255) NOT NULL
);
CREATE SEQUENCE groups
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE groups_id_seq OWNED BY groups.id;
ALTER TABLE ONLY pricing_groups ALTER COLUMN id SET DEFAULT nextval('groups_id_seq'::regclass);
ALTER TABLE ONLY groups
ADD CONSTRAINT groups_pkey PRIMARY KEY (id);