原则2-重复密钥更新


Doctrine 2 - On duplicate key update

我有一个用户实体,它使用多对多联接表与角色实体相关联。

我的问题是当我来更新它。

它抛出以下错误:

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'

现在,如果我正确理解了这一点,那么问题是我正在尝试插入另一行,该行具有已经存在的主键。

连接下面生成的原理表模式。

+---------+---------+------+-----+---------+-------+
| Field   | Type    | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| user_id | int(11) | NO   | PRI | NULL    |       |
| role_id | int(11) | NO   | PRI | NULL    |       |
+---------+---------+------+-----+---------+-------+

My User实体有一个方法setRoles(),它会将角色添加到ArrayCollection,然后条令会尝试执行插入。

所以我想我想问的是,在学说中是否有一种关于重复键的方法?

或者有人能给我一些指导,告诉我如何实现这一点,即使这意味着要重新生成一个模式。

我是新的学说,我已经遵循了初学者教程,仍然在仔细考虑文档。

编辑

<?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;
    }
}

感谢

Adam

@Adam ArrayCollection上有一些函数用于检查它。前两个函数是containsindexOf,它们在内部使用in_arrayarray_search,所以我认为您需要传入的Role与加载到集合中的Identity映射中的实例相同,因为它测试引用相等性。第三个是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();
    });
}

当然,您可以更改该方法以比较更多字段或其他内容,或者允许传入一组字段进行比较,但在这种情况下似乎不需要这样做。

感谢您的所有输入:-)。

好吧,由于我缺乏理解,我不知道mysql复合密钥,这要感谢@magitalson指出的。

以下是我在用户实体中实现的内容,用于检查复合键是否不存在,如果不存在,则执行插入。感谢@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