Я работаю над members
импорта members
(с вставками и обновлениями) для большого проекта с большим количеством объектов, таких как Member
, Client
, Group
, ...
После прочтения главы, посвященной объемному импорту в докторе Доктрины, я внедрил этот код:
$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
, Doctrine пытается вставить нулевые данные в полностью другую таблицу, связанную с объектом Group
и генерируется исключение An exception occurred while executing 'INSERT INTO groups ...
Между Member
и Group
нет никаких отношений …
Любая идея об этом странном поведении?
РЕДАКТИРОВАТЬ
Краткие сведения о карте:
/** * @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; } }
как/** * @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);
Я могу описать причину ошибки, но только угадать, почему она вызвана, и дать некоторые подсказки о том, что нужно искать при отладке этого.
Как вы описали, вы обновляете членов, которые являются частью клиента, который, в свою очередь, является частью группы. Как вы указали в отношениях cascade=persist
, клиенты и группы сохраняются также при сохранении члена. Это означает, что группы либо обновляются, либо создаются при вставке элементов. В вашем случае вы создаете новую группу по этому механизму. Тем не менее эта группа не имеет набора свойств label
, что приводит к значению NULL
в базе данных, которое не допускается схемой.
Как вы сказали, эта ошибка уже происходит во время самой лучшей партии. Один из первых 20 членов, которых вы обновляете, создает новую группу без метки. Чтобы выяснить, какой из них я предлагаю, используйте отладчик и проверяйте каждого члена до настойчивости, чтобы узнать, чем является группа этого члена, и если он существует в базе данных. Если он не существует (по ID
), вы должны выяснить, почему эта группа не является обязательным набором ярлыков.
Если все группы действительно существуют в базе данных уже, все становится немного сложнее, и это зависит от того, как загружаются члены, которые вы обновляете. Получены ли они из EntityManager ( managed
состояние) или они загружаются из другого источника (например, serialized
) и, следовательно, в unmanaged
состоянии? Если они неуправляемы, они станут управляться на основе существования, а также путем определения отношения cascade=merge
, client и group также будут управляться. Однако здесь важно знать, что merge
вернет новый (управляемый) объект, который затем сохраняется (см. Принятый ответ здесь ). Поскольку это новый объект, возможно, существует вероятность того, что этот объект не полностью инициализирован и может содержать неопределенные значения (которые затем будут переведены в NULL
). Поэтому при загрузке данных member
из другого источника, кроме EntityManager, вам сначала придется связать их с EntityManager, чтобы избежать этой проблемы.
Отладка последнего довольно сложна, и вам нужно будет войти в метод UnitOfWork->doPersist
чтобы увидеть, как фактическое сохранение каждого отдельного объекта.