2016-03-31 50 views
2

我工作的一個members進口批次(與插入和更新)工作。Doctrine2批量導入嘗試與很多實體,如<code>Member</code>,<code>Client</code>,<code>Group</code>,<code>...</code>的一個大項目的另一個實體

讀取與散裝進口主義文檔的章節後,我實現了這個代碼:

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

現在,當我要批量處理Member實體的陣列,學說試圖插入空數據進入相關Group實體,拋出一個異常An exception occurred while executing 'INSERT INTO groups ...

有沒有MemberGroup之間的任何關係,完全其它表...

關於這個奇怪行爲的任何想法?

EDIT

短映射的細節:

/** 
* @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; 
    } 
} 

和錯誤的類型爲:

An exception occurred while executing 'INSERT INTO groups ... SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column "label" violates not-null constraint DETAIL: Failing row contains (60, null, f, null, f, null, null).

EDIT2

這是表創建描述(使用PostgreSQL ):

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

有沒有可能將這兩個類的映射細節添加到問題中?你有沒有嘗試過使用調試器來遍歷這個循環,看看這個異常是否已經在第一次循環迭代或僅僅在後面的迭代中發生? – Fge

+0

嗨Fge,抱歉我遲到的答案...請檢查我的編輯,以獲得有關此問題的更多詳細信息。感謝您的時間 – ceadreak

+0

我使用了一個調試器,但在第一次插入時出現錯誤flush – ceadreak

回答

1

我可以描述是什麼導致了錯誤,但只能猜出它是什麼原因造成的,並且提供了一些提示,說明在調試時要查找什麼。

正如您所描述的那樣,您正在更新作爲客戶端的一部分的成員,這些成員又是組的一部分。正如您在cascade=persist中指定的關係那樣,在保存成員時,也可以保存客戶端和組。這意味着,組在插入成員時更新或創建。在你的情況下,你正在通過這個機制創建一個新的組。然而,該組沒有label屬性集,導致數據庫中的值爲NULL,這是方案不允許的。

正如你所說,這個錯誤已經發生在最好的批次。你更新暗示的前20名成員之一會創建一個沒有標籤的新組。要找出它是哪一個,我建議使用一個調試器,然後檢查每個成員,然後再查看該成員的組是什麼,以及它是否存在於數據庫中。如果它不存在(由ID),你應該調查爲什麼這個組沒有所需的標籤集。

如果所有組確實已經存在於數據庫中,事情會變得更加棘手,這取決於您正在更新的成員如何加載。它們是從EntityManager中獲取的(managed狀態)還是從某個不同的來源加載(例如serialized),因此是unmanaged狀態?如果他們是不受管理的,他們將成爲持續管理,並通過關係cascade=merge的規範,客戶和組,也將成爲管理。這裏有一個重要的事情要知道,merge將返回一個新的(託管)實體,然後這個實體被保留(請參閱accepted answer here)。由於這是一個新對象,因此可能有此對象未完全初始化並可能包含未定義的值(然後轉換爲NULL)。 因此,當從不同於EntityManager的源加載member數據時,可能必須先將它們與EntityManager進行連接以避免此問題。

調試最後一個是非常困難的,你需要進入UnitOfWork->doPersist方法,看看每個實體如何實際持久。

+0

@ Fge,謝謝您的明確回答。此錯誤出現在第一次插入/更新時。 MayTo cascade = {「persist」,「merge」} ManyToOne Client :: $ group'和'Member :: $ client'是導致此行爲的原因。保存批量方法與「正常」保存方法確實相同。唯一不同的是'EntityManager'清除。我會以這種方式進行調查。 +1爲這個偉大的答案 – ceadreak

相關問題