Doctrine 2 - 关于重复密钥更新
Doctrine 2 - On duplicate key update
我有一个用户实体,它使用多对多连接与角色实体关联 table。
我的问题是什么时候来更新
它抛出以下错误:
An exception occurred while executing 'INSERT INTO user_role (user_id, role_id) VALUES (?, ?)' with params [38, 3]:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '38-3' for key 'PRIMARY'
现在,如果我理解正确,问题是我正在尝试插入另一行,其中的主键已经存在。
加入table 学说在下面生成的模式。
+---------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| user_id | int(11) | NO | PRI | NULL | |
| role_id | int(11) | NO | PRI | NULL | |
+---------+---------+------+-----+---------+-------+
我的用户实体有一个方法 setRoles(),它将角色添加到 ArrayCollection,然后 doctrine 将尝试执行插入。
所以我想我想问的是学说中是否有重复键方法?
或者有人可以给我一些关于如何实现这一目标的指导,即使这意味着重新生成一个模式。
我是 doctrine 的新手,我已经遵循了初学者教程并且仍在仔细研究文档。
编辑
<?php
namespace Brs\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
class User implements UserInterface, \Serializable
{
private $id;
private $username;
private $fname;
private $lname;
private $email;
private $mobile;
private $active;
private $mentor;
private $initialized;
private $roles;
private $password;
private $tempPassword;
public function __construct(){
$this->roles = new ArrayCollection();
}
public function getTempPassword(){
return $this->tempPassword;
}
public function setTempPassword($tempPassword){
$this->tempPassword = $tempPassword;
return $this;
}
public function getUsername(){
return $this->username;
}
public function getSalt(){
return null;
}
public function getPassword(){
return $this->password;
}
public function getRoles(){
return $this->roles->toArray();
}
public function getRole(){
return $this->roles;
}
public function setRoles($roles){
$this->roles[] = $roles;
return $this;
}
public function eraseCredentials(){
}
public function serialize(){
return serialize(array(
$this->id,
$this->username,
$this->password,
));
}
public function unserialize($serialized){
list(
$this->id,
$this->username,
$this->password,
) = unserialize($serialized);
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set username
*
* @param string $username
* @return User
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Set fname
*
* @param string $fname
* @return User
*/
public function setFname($fname)
{
$this->fname = $fname;
return $this;
}
/**
* Get fname
*
* @return string
*/
public function getFname()
{
return $this->fname;
}
/**
* Set lname
*
* @param string $lname
* @return User
*/
public function setLname($lname)
{
$this->lname = $lname;
return $this;
}
/**
* Get lname
*
* @return string
*/
public function getLname()
{
return $this->lname;
}
/**
* Set email
*
* @param string $email
* @return User
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set mobile
*
* @param string $mobile
* @return User
*/
public function setMobile($mobile)
{
$this->mobile = $mobile;
return $this;
}
/**
* Get mobile
*
* @return string
*/
public function getMobile()
{
return $this->mobile;
}
/**
* Set active
*
* @param boolean $active
* @return User
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
/**
* Get active
*
* @return boolean
*/
public function getActive()
{
return $this->active;
}
/**
* Set mentor
*
* @param boolean $mentor
* @return User
*/
public function setMentor($mentor)
{
$this->mentor = $mentor;
return $this;
}
/**
* Get mentor
*
* @return boolean
*/
public function getMentor()
{
return $this->mentor;
}
/**
* Set initialized
*
* @param \DateTime $initialized
* @return User
*/
public function setInitialized($initialized)
{
$this->initialized = $initialized;
return $this;
}
/**
* Get initialized
*
* @return \DateTime
*/
public function getInitialized()
{
return $this->initialized;
}
/**
* Set password
*
* @param string $password
* @return User
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* @var \Doctrine\Common\Collections\Collection
*/
private $targetEntity;
/**
* @var \Doctrine\Common\Collections\Collection
*/
private $inversedBy;
/**
* Add targetEntity
*
* @param \Brs\UserBundle\Entity\R $targetEntity
* @return User
*/
public function addTargetEntity(\Brs\UserBundle\Entity\R $targetEntity)
{
$this->targetEntity[] = $targetEntity;
return $this;
}
/**
* Remove targetEntity
*
* @param \Brs\UserBundle\Entity\R $targetEntity
*/
public function removeTargetEntity(\Brs\UserBundle\Entity\R $targetEntity)
{
$this->targetEntity->removeElement($targetEntity);
}
/**
* Get targetEntity
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getTargetEntity()
{
return $this->targetEntity;
}
/**
* Add inversedBy
*
* @param \Brs\UserBundle\Entity\u $inversedBy
* @return User
*/
public function addInversedBy(\Brs\UserBundle\Entity\u $inversedBy)
{
$this->inversedBy[] = $inversedBy;
return $this;
}
/**
* Remove inversedBy
*
* @param \Brs\UserBundle\Entity\u $inversedBy
*/
public function removeInversedBy(\Brs\UserBundle\Entity\u $inversedBy)
{
$this->inversedBy->removeElement($inversedBy);
}
/**
* Get inversedBy
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getInversedBy()
{
return $this->inversedBy;
}
/**
* Add roles
*
* @param \Brs\UserBundle\Entity\Role $roles
* @return User
*/
public function addRole(\Brs\UserBundle\Entity\Role $roles)
{
$this->roles[] = $roles;
return $this;
}
/**
* Remove roles
*
* @param \Brs\UserBundle\Entity\Role $roles
*/
public function removeRole(\Brs\UserBundle\Entity\Role $roles)
{
$this->roles->removeElement($roles);
}
}
角色实体:
<?php
namespace Brs\UserBundle\Entity;
use Symfony\Component\Security\Core\Role\RoleInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
class Role implements RoleInterface{
private $id;
private $name;
private $role;
private $users;
public function __construct(){
$this->users = new ArrayCollection();
}
public function getRole(){
return $this->role;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Role
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set role
*
* @param string $role
* @return Role
*/
public function setRole($role)
{
$this->role = $role;
return $this;
}
/**
* Add users
*
* @param \Brs\UserBundle\Entity\User $users
* @return Role
*/
public function addUser(\Brs\UserBundle\Entity\User $users)
{
$this->users[] = $users;
return $this;
}
/**
* Remove users
*
* @param \Brs\UserBundle\Entity\User $users
*/
public function removeUser(\Brs\UserBundle\Entity\User $users)
{
$this->users->removeElement($users);
}
/**
* Get users
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getUsers()
{
return $this->users;
}
}
谢谢
亚当
感谢您的所有意见 :-)。
好吧,由于我缺乏理解,我不知道 mysql 复合键,感谢@prodigitalson 指出了这一点。
这是我在我的用户实体中实现的,用于检查组合键是否不存在,如果不存在则执行插入。
感谢@kmlnvm 的指导。
private $roleIds = array();
public function setRoles($role){
if($role !== null){
foreach($this->getRoles() as $currentRole){
$this->roleIds[] = $currentRole->getId();
}
if(!in_array($role->getId(),$this->roleIds)){
$this->roles[] = $role;
}
}
return $this;
}
我想输入我已经实现的内容,这是执行此操作的好方法吗?
谢谢
亚当
@Adam ArrayCollection
上有检查它的功能。前两个是 contains
和 indexOf
- 它们在内部使用 in_array
和 array_search
所以我认为您需要传入的 Role 与加载到集合中的标识映射 - 因为它测试引用相等性。第三,exists
允许您传入闭包以用作比较函数。
我会在 User
实体的 hasRole
方法中使用这些方法之一:
public function hasRole(Role $role) {
return $this->getRoles()->contains($role);
}
如果出于某种原因您需要使用 exists
而不是,它可能看起来像:
public function hasRole(Role $role) {
return $this->getRoles()->exists(function($key, $entity) use ($role) {
return $entity->getId() === $role->getId();
});
}
您当然可以更改该方法以比较更多字段或其他内容,或者允许您传入一组字段进行比较,但在这种情况下似乎不需要这样做。
我有一个用户实体,它使用多对多连接与角色实体关联 table。
我的问题是什么时候来更新
它抛出以下错误:
An exception occurred while executing 'INSERT INTO user_role (user_id, role_id) VALUES (?, ?)' with params [38, 3]:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '38-3' for key 'PRIMARY'
现在,如果我理解正确,问题是我正在尝试插入另一行,其中的主键已经存在。
加入table 学说在下面生成的模式。
+---------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| user_id | int(11) | NO | PRI | NULL | |
| role_id | int(11) | NO | PRI | NULL | |
+---------+---------+------+-----+---------+-------+
我的用户实体有一个方法 setRoles(),它将角色添加到 ArrayCollection,然后 doctrine 将尝试执行插入。
所以我想我想问的是学说中是否有重复键方法?
或者有人可以给我一些关于如何实现这一目标的指导,即使这意味着重新生成一个模式。
我是 doctrine 的新手,我已经遵循了初学者教程并且仍在仔细研究文档。
编辑
<?php
namespace Brs\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
class User implements UserInterface, \Serializable
{
private $id;
private $username;
private $fname;
private $lname;
private $email;
private $mobile;
private $active;
private $mentor;
private $initialized;
private $roles;
private $password;
private $tempPassword;
public function __construct(){
$this->roles = new ArrayCollection();
}
public function getTempPassword(){
return $this->tempPassword;
}
public function setTempPassword($tempPassword){
$this->tempPassword = $tempPassword;
return $this;
}
public function getUsername(){
return $this->username;
}
public function getSalt(){
return null;
}
public function getPassword(){
return $this->password;
}
public function getRoles(){
return $this->roles->toArray();
}
public function getRole(){
return $this->roles;
}
public function setRoles($roles){
$this->roles[] = $roles;
return $this;
}
public function eraseCredentials(){
}
public function serialize(){
return serialize(array(
$this->id,
$this->username,
$this->password,
));
}
public function unserialize($serialized){
list(
$this->id,
$this->username,
$this->password,
) = unserialize($serialized);
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set username
*
* @param string $username
* @return User
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Set fname
*
* @param string $fname
* @return User
*/
public function setFname($fname)
{
$this->fname = $fname;
return $this;
}
/**
* Get fname
*
* @return string
*/
public function getFname()
{
return $this->fname;
}
/**
* Set lname
*
* @param string $lname
* @return User
*/
public function setLname($lname)
{
$this->lname = $lname;
return $this;
}
/**
* Get lname
*
* @return string
*/
public function getLname()
{
return $this->lname;
}
/**
* Set email
*
* @param string $email
* @return User
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set mobile
*
* @param string $mobile
* @return User
*/
public function setMobile($mobile)
{
$this->mobile = $mobile;
return $this;
}
/**
* Get mobile
*
* @return string
*/
public function getMobile()
{
return $this->mobile;
}
/**
* Set active
*
* @param boolean $active
* @return User
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
/**
* Get active
*
* @return boolean
*/
public function getActive()
{
return $this->active;
}
/**
* Set mentor
*
* @param boolean $mentor
* @return User
*/
public function setMentor($mentor)
{
$this->mentor = $mentor;
return $this;
}
/**
* Get mentor
*
* @return boolean
*/
public function getMentor()
{
return $this->mentor;
}
/**
* Set initialized
*
* @param \DateTime $initialized
* @return User
*/
public function setInitialized($initialized)
{
$this->initialized = $initialized;
return $this;
}
/**
* Get initialized
*
* @return \DateTime
*/
public function getInitialized()
{
return $this->initialized;
}
/**
* Set password
*
* @param string $password
* @return User
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* @var \Doctrine\Common\Collections\Collection
*/
private $targetEntity;
/**
* @var \Doctrine\Common\Collections\Collection
*/
private $inversedBy;
/**
* Add targetEntity
*
* @param \Brs\UserBundle\Entity\R $targetEntity
* @return User
*/
public function addTargetEntity(\Brs\UserBundle\Entity\R $targetEntity)
{
$this->targetEntity[] = $targetEntity;
return $this;
}
/**
* Remove targetEntity
*
* @param \Brs\UserBundle\Entity\R $targetEntity
*/
public function removeTargetEntity(\Brs\UserBundle\Entity\R $targetEntity)
{
$this->targetEntity->removeElement($targetEntity);
}
/**
* Get targetEntity
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getTargetEntity()
{
return $this->targetEntity;
}
/**
* Add inversedBy
*
* @param \Brs\UserBundle\Entity\u $inversedBy
* @return User
*/
public function addInversedBy(\Brs\UserBundle\Entity\u $inversedBy)
{
$this->inversedBy[] = $inversedBy;
return $this;
}
/**
* Remove inversedBy
*
* @param \Brs\UserBundle\Entity\u $inversedBy
*/
public function removeInversedBy(\Brs\UserBundle\Entity\u $inversedBy)
{
$this->inversedBy->removeElement($inversedBy);
}
/**
* Get inversedBy
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getInversedBy()
{
return $this->inversedBy;
}
/**
* Add roles
*
* @param \Brs\UserBundle\Entity\Role $roles
* @return User
*/
public function addRole(\Brs\UserBundle\Entity\Role $roles)
{
$this->roles[] = $roles;
return $this;
}
/**
* Remove roles
*
* @param \Brs\UserBundle\Entity\Role $roles
*/
public function removeRole(\Brs\UserBundle\Entity\Role $roles)
{
$this->roles->removeElement($roles);
}
}
角色实体:
<?php
namespace Brs\UserBundle\Entity;
use Symfony\Component\Security\Core\Role\RoleInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
class Role implements RoleInterface{
private $id;
private $name;
private $role;
private $users;
public function __construct(){
$this->users = new ArrayCollection();
}
public function getRole(){
return $this->role;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Role
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set role
*
* @param string $role
* @return Role
*/
public function setRole($role)
{
$this->role = $role;
return $this;
}
/**
* Add users
*
* @param \Brs\UserBundle\Entity\User $users
* @return Role
*/
public function addUser(\Brs\UserBundle\Entity\User $users)
{
$this->users[] = $users;
return $this;
}
/**
* Remove users
*
* @param \Brs\UserBundle\Entity\User $users
*/
public function removeUser(\Brs\UserBundle\Entity\User $users)
{
$this->users->removeElement($users);
}
/**
* Get users
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getUsers()
{
return $this->users;
}
}
谢谢
亚当
感谢您的所有意见 :-)。
好吧,由于我缺乏理解,我不知道 mysql 复合键,感谢@prodigitalson 指出了这一点。
这是我在我的用户实体中实现的,用于检查组合键是否不存在,如果不存在则执行插入。 感谢@kmlnvm 的指导。
private $roleIds = array();
public function setRoles($role){
if($role !== null){
foreach($this->getRoles() as $currentRole){
$this->roleIds[] = $currentRole->getId();
}
if(!in_array($role->getId(),$this->roleIds)){
$this->roles[] = $role;
}
}
return $this;
}
我想输入我已经实现的内容,这是执行此操作的好方法吗?
谢谢
亚当
@Adam ArrayCollection
上有检查它的功能。前两个是 contains
和 indexOf
- 它们在内部使用 in_array
和 array_search
所以我认为您需要传入的 Role 与加载到集合中的标识映射 - 因为它测试引用相等性。第三,exists
允许您传入闭包以用作比较函数。
我会在 User
实体的 hasRole
方法中使用这些方法之一:
public function hasRole(Role $role) {
return $this->getRoles()->contains($role);
}
如果出于某种原因您需要使用 exists
而不是,它可能看起来像:
public function hasRole(Role $role) {
return $this->getRoles()->exists(function($key, $entity) use ($role) {
return $entity->getId() === $role->getId();
});
}
您当然可以更改该方法以比较更多字段或其他内容,或者允许您传入一组字段进行比较,但在这种情况下似乎不需要这样做。