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