【问题标题】:Symfony2 Doctrine2 trouble with optional one to one relationSymfony2 Doctrine2 问题与可选的一对一关系
【发布时间】:2013-03-22 13:54:15
【问题描述】:

我对 Symfony2 中的 Doctrine2 和两个相关实体有疑问。

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

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

当然我想将两者保存在一起,因此保存用户必须创建或更新用户元实体。

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

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

请注意 User->setMeta.. 中的 cmets。

/**
 * 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();
    }
...

【问题讨论】:

  • 设置元不是技巧 - nullable=true /** * @var Usermeta * @ORM\OneToOne(targetEntity="Usermeta", mappedBy="user", cascade={"persist "}, nullable=true) */ protected $meta;
  • @Zdenek,OneToOne 注释没有可为空的参数。是@JoinColumn的参数。

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


【解决方案1】:

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

您想要的是从 UsermetaUserunidirectional one to one

双向的一对一关系意味着:

  1. 用户必须有一个 Usermeta 对象。
  2. Usermeta 对象必须有一个用户。

在你的情况下,你只是试图要求第二个条件。

这确实意味着您只能从 Usermeta 中对用户进行水合,而不是相反。

不幸的是教条does not support Zero or One to Many关系。

【讨论】:

    【解决方案2】:

    阅读我自己的老问题很有趣,因为我现在第一眼就看到了问题..

    当谈到一个解决方案时,我认为教义只能处理名为“id”的 ID,但是 ... aduserid 只是没有标记为 ID,它缺少 Id 注释,并且教义不能使用该字段进行连接列..

    第二件事,Zdenek Machek 是对的:必须将其标记为可为空。

    【讨论】:

      【解决方案3】:

      我在尝试同样的事情时收到错误消息 “spl_object_hash() 期望参数 1 是对象,null 在...中给出”。我试图定义一个双向的One to One 关系,而反转的值可以是null。这给出了错误消息。去掉关系的反面就解决了这个问题。 可惜不支持Zero or One to One关系。

      【讨论】:

        【解决方案4】:

        我希望我提交这个很晚的答案不会打扰任何人,但这是我解决这个问题的方法:

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

        我在属性声明中添加了= null;。我希望这对阅读本文的人有所帮助。

        【讨论】:

        • 任何类字段的默认值为null。
        【解决方案5】:

        Zdenek Machek 评论几乎是正确的。正如您从 Doctrine2 文档中看到的那样,nullable 选项应该在连接注释 (@JoinColumn) 中,而不是在映射之一 (@OneToOne em>)。

        @JoinColumn 文档:

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

        必需的属性:

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

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

        可选属性:

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

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

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

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

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

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

        @OneToOne 文档:

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

        必需的属性:

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

        可选属性:

        级联:级联选项

        fetch:LAZY 或 EAGER 之一

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

        inversedBy:inversedBy 属性指定实体中作为关系反面的字段。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-26
          • 2011-09-24
          • 1970-01-01
          • 2012-08-09
          • 1970-01-01
          相关资源
          最近更新 更多