Symfony2 Doctrine2与可选的一对一关系出现问题

时间:2013-04-01 13:22:47

标签: symfony orm doctrine-orm one-to-one

我在Symfony2和两个关系实体中遇到Doctrine2问题。

有一个用户实体,可以(不是必须)引用的usermeta-entity包含传记等信息。

usermeta是可选的,因为用户是由另一个系统导入的,而usermeta是在我的应用程序中管理的。

当然我想将两者保存在一起,以便保存用户必须创建或更新usermeta-entity。

两者都由名为aduserid的列连接(两个表中的名称相同)。

我已经认识到如果usermeta是一个可选引用,在这种情况下,拥有方应该是usermeta,否则doctrine会加载用户并需要usermeta实体 - 但它并不总是存在。

请注意User-> setMeta ..

中的评论
/**
 * User
 *
 * @ORM\Table(name="user")
 * @ORM\Entity
 */
class User
{
/**
 * @var Usermeta
 * @ORM\OneToOne(targetEntity="Usermeta", mappedBy="user", cascade={"persist"})
 */
protected $meta;

public function getMeta()
{
    return $this->meta;
}

/**
 * 
 * @param Usermeta $metaValue 
 */
public function setMeta($metaValue)
{        
// I've tried setting the join-column-value here 
//  - but it's not getting persisted
// $metaValue->setAduserid($this->getAduserid());

// Then I've tried to set the user-object in Usermeta - but then 
//  it seems like Doctrine wants to update Usermeta and searches
//  for ValId names aduserid (in BasicEntityPersister->_prepareUpdateData) 
//  but only id is given -  so not luck here
// $metaValue->setUser($this);           

    $this->meta = $metaValue;
}

/**
 * @var integer
 *
 * @ORM\Column(name="rowid", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $id;


/**
 * Get rowid
 *
 * @return integer 
 */
public function getId()
{
    return $this->id;
}

/**
 * @var integer
 *
 * @ORM\Column(name="ADuserid", type="integer", nullable=false)
 */
private $aduserid;

/**
 * Set aduserid
 *
 * @param integer $aduserid
 * @return User
 */
public function setAduserid($aduserid)
{
    $this->aduserid = $aduserid;

    return $this;
}

/**
 * Get aduserid
 *
 * @return integer 
 */
public function getAduserid()
{
    return $this->aduserid;
}

// some mor fields.... 
}

Usermeta课程:

/**
 * Usermeta
 *
 * @ORM\Table(name="userMeta")
 * @ORM\Entity
 */
class Usermeta
{
/**
 * @ORM\OneToOne(targetEntity="User", inversedBy="meta")
 * @ORM\JoinColumn(name="ADuserid", referencedColumnName="ADuserid")
 */
protected $user;

public function getUser()
{
    return $this->$user;
}    

public function setUser($userObj)
{
    $this->user = $userObj;
}

/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $id;

/**
 * @var integer
 *
 * @ORM\Column(name="ADuserid", type="integer", nullable=false)
 */
private $aduserid;

/**
 * Set aduserid
 *
 * @param integer $aduserid
 * @return User
 */
public function setAduserid($aduserid)
{
    $this->aduserid = $aduserid;

    return $this;
}

/**
 * Get aduserid
 *
 * @return integer 
 */
public function getAduserid()
{
    return $this->aduserid;
}
}

控制器代码如下所示:

...

$userForm->bind($request);

    if($userForm->isValid()) {
        $em->persist($user);
        $em->flush();
    }
...

5 个答案:

答案 0 :(得分:16)

Zdenek Machek 评论几乎是正确的。从Doctrine2文档中可以看出, nullable 选项应该在连接注释( @JoinColumn )中,而不是在映射中( @OneToOne )。

@JoinColumn doc:

  

此注释用于@ManyToOne,@ OneToOne字段和嵌套在@ManyToMany中的@JoinTable的上下文中的关系的上下文中。此注释不是必需的。如果未指定,则从表和主键名称推断出属性name和referencedColumnName。

     

必需属性:

     

name :包含此关系的外键标识符的列名。在@JoinTable的上下文中,它指定了连接表中的列名。

     

referencedColumnName :用于加入此关系的主键标识符的名称。

     

可选属性:

     

唯一:确定此关系是否在受影响的实体之间是独占的,并且应该在数据库约束级别上强制执行。默认为false。

     

nullable:确定相关实体是否是必需的,或者null是否为关系的允许状态。默认为true。

     

onDelete :级联操作(数据库级)

     

onUpdate :级联操作(数据库级)

     

columnDefinition :在列名后面开始并指定完整(非可移植!)列定义的DDL SQL代码段。此属性允许使用高级RMDBS功能。如果您需要稍微不同的列定义来连接列,则必须在@JoinColumn上使用此属性,例如关于NULL / NOT NULL默认值。但是,默认情况下,@ Column上的“columnDefinition”属性也会设置相关的@ JoinColumn的columnDefinition。这是使外键工作所必需的。

http://doctrine-orm.readthedocs.org/en/latest/reference/annotations-reference.html#annref-joincolumn

@OneToOne doc:

  

@OneToOne注释与@ManyToOne的工作方式几乎完全相同,并且可以指定一个附加选项。 @JoinColumn的配置默认使用目标实体表,主键列名也适用于此。

     

必需属性:

     

targetEntity :引用的目标实体的FQCN。如果两个类都在同一名称空间中,则可以是非限定类名。重要提示:没有领先的反斜杠!

     

可选属性:

     

级联:级联选项

     

获取:LAZY或EAGER之一

     

orphanRemoval :布尔值,指定是否应该通过Doctrine删除孤立,即未连接到任何拥有实例的反向OneToOne实体。默认为false。

     

inversedBy :inversedBy属性指定实体中与关系相反的字段。

http://doctrine-orm.readthedocs.org/en/latest/reference/annotations-reference.html#onetoone

答案 1 :(得分:7)

您的问题使用了错误的关系类型。

您想要的是从 Usermeta 用户unidirectional one to one

双向一对一关系意味着以下内容:

  1. 用户必须拥有Usermeta对象。
  2. Usermeta对象必须有一个用户。
  3. 在你的情况下,你只是想要第二个条件。

    这意味着您只能从Usermeta中保留用户,而不是相反。

    不幸的是学说does not support Zero or One to Many关系。

答案 2 :(得分:0)

我收到错误消息“spl_object_hash()期望参数1为对象,在尝试相同的事情时在...”中给出null。我尝试定义双向One to One关系,而反转值可能是null。这给出了错误消息。剥夺了关系的反面解决了问题。 遗憾的是,Zero or One to One关系不受支持。

答案 3 :(得分:0)

我希望通过提交这个非常晚的答案来打扰任何人,但这是我如何解决这个问题:

/**
 * @var Takeabyte\GripBundle\Entity\PDF
 * @ORM\OneToOne(targetEntity="Takeabyte\GripBundle\Entity\PDF", inversedBy="element", fetch="EAGER", orphanRemoval=true)
 */
protected $pdf = null;

我在属性声明中添加了= null;。我希望这对任何阅读此内容的人都有任何帮助。

答案 4 :(得分:-4)

阅读我自己的旧问题非常有趣,因为我现在第一眼就看到了这个问题..

当谈到解决方案时,我认为该学说只能处理名为“id”的ID,但是... aduserid只是没有标记为ID,它缺少Id注释,而且学说不能使用这些字段进行连接专栏..

第二件事,Zdenek Machek是对的:它必须被标记为可以为空。