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

时间:2021-04-26 06:46:30

I have a problem with Doctrine2 in Symfony2 and two relationed entities.

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

There is a user-entity that can (not must) have a usermeta-entity referenced which contains information like biography etc.

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

The usermeta is optional because user is imported by another system, while usermeta is managed in my application.

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

Of course I want to save both together, so that saving a user must create or update a usermeta-entity.

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

Both are joined by a column named aduserid (same name in both tables).

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

I've recognized that if usermeta is an optional reference the owning-side in this case should be usermeta, otherwise doctrine loads user and needs the usermeta entity - but it's not always there.

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

Please note the comments in User->setMeta..

请注意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.... 
}

And the Usermeta class:

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

the controller code looks like this:

控制器代码如下所示:

...

$userForm->bind($request);

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

5 个解决方案

#1


14  

The Zdenek Machek comment is almost correct. As you can see from the Doctrine2 documentation, the nullable option should be in the join annotation (@JoinColumn), not in the mapping one (@OneToOne).

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

@JoinColumn doc:

@JoinColumn doc:

This annotation is used in the context of relations in @ManyToOne, @OneToOne fields and in the Context of @JoinTable nested inside a @ManyToMany. This annotation is not required. If its not specified the attributes name and referencedColumnName are inferred from the table and primary key names.

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

Required attributes:

必需属性:

name: Column name that holds the foreign key identifier for this relation. In the context of @JoinTable it specifies the column name in the join table.

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

referencedColumnName: Name of the primary key identifier that is used for joining of this relation.

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

Optional attributes:

可选属性:

unique: Determines if this relation exclusive between the affected entities and should be enforced so on the database constraint level. Defaults to false.

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

nullable: Determine if the related entity is required, or if null is an allowed state for the relation. Defaults to true.

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

onDelete: Cascade Action (Database-level)

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

onUpdate: Cascade Action (Database-level)

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

columnDefinition: DDL SQL snippet that starts after the column name and specifies the complete (non-portable!) column definition. This attribute allows to make use of advanced RMDBS features. Using this attribute on @JoinColumn is necessary if you need slightly different column definitions for joining columns, for example regarding NULL/NOT NULL defaults. However by default a “columnDefinition” attribute on @Column also sets the related @JoinColumn’s columnDefinition. This is necessary to make foreign keys work.

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

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

@OneToOne doc:

@OneToOne doc:

The @OneToOne annotation works almost exactly as the @ManyToOne with one additional option that can be specified. The configuration defaults for @JoinColumn using the target entity table and primary key column names apply here too.

@OneToOne注释几乎与@ManyToOne一样,只能指定一个附加选项。 @JoinColumn的配置默认值使用目标实体表,主键列名也适用于此处。

Required attributes:

必需属性:

targetEntity: FQCN of the referenced target entity. Can be the unqualified class name if both classes are in the same namespace. IMPORTANT: No leading backslash!

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

Optional attributes:

可选属性:

cascade: Cascade Option

级联:级联选项

fetch: One of LAZY or EAGER

获取:LAZY或EAGER之一

orphanRemoval: Boolean that specifies if orphans, inverse OneToOne entities that are not connected to any owning instance, should be removed by Doctrine. Defaults to false.

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

inversedBy: The inversedBy attribute designates the field in the entity that is the inverse side of the relationship.

inversedBy:inversedBy属性指定实体中的场,该场是关系的反面。

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

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

#2


7  

You're using the wrong type of Relation for your problem.

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

What you want is a unidirectional one to one from Usermeta to User.

你想要的是从Usermeta到User的单向一对一。

A bidirectional one to one relationship would mean the following:

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

  1. A user MUST have a Usermeta object.
  2. 用户必须拥有Usermeta对象。
  3. A Usermeta object MUST have a User.
  4. Usermeta对象必须有一个用户。

In your case you're only trying to require the second condition.

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

This does mean that you can only hydrate User from Usermeta and not the other way around.

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

Unfortunately doctrine does not support Zero or One to Many relationships.

不幸的是,学说不支持零或一对多的关系。

#3


0  

I got the error message "spl_object_hash() expects parameter 1 to be object, null given in..." while trying the same thing. I tried to define a bidirectional One to One relationship while the inversed value could be null. This gave the error message. Taking away the inversed side of the relationship solved the problem. It is a pity that Zero or One to One relationships aren't supported.

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

#4


0  

I hope I do not disturb anyone by submitting this very late answer, but here is how I solved this problem:

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

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

I added = null; to the attribute declaration. I hope this is of any help for anyone who reads this.

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

#5


-4  

Reading my own old question is quite fun since I see the problem at first glance now..

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

When it came to a solution I've thought that doctrine can only handle Ids named "id", but ... aduserid is just not marked as ID, it's missing the Id annotation and doctrine cannot use the fields for the join column..

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

Second thing, Zdenek Machek was right: It has to be marked as nullable.

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

#1


14  

The Zdenek Machek comment is almost correct. As you can see from the Doctrine2 documentation, the nullable option should be in the join annotation (@JoinColumn), not in the mapping one (@OneToOne).

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

@JoinColumn doc:

@JoinColumn doc:

This annotation is used in the context of relations in @ManyToOne, @OneToOne fields and in the Context of @JoinTable nested inside a @ManyToMany. This annotation is not required. If its not specified the attributes name and referencedColumnName are inferred from the table and primary key names.

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

Required attributes:

必需属性:

name: Column name that holds the foreign key identifier for this relation. In the context of @JoinTable it specifies the column name in the join table.

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

referencedColumnName: Name of the primary key identifier that is used for joining of this relation.

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

Optional attributes:

可选属性:

unique: Determines if this relation exclusive between the affected entities and should be enforced so on the database constraint level. Defaults to false.

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

nullable: Determine if the related entity is required, or if null is an allowed state for the relation. Defaults to true.

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

onDelete: Cascade Action (Database-level)

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

onUpdate: Cascade Action (Database-level)

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

columnDefinition: DDL SQL snippet that starts after the column name and specifies the complete (non-portable!) column definition. This attribute allows to make use of advanced RMDBS features. Using this attribute on @JoinColumn is necessary if you need slightly different column definitions for joining columns, for example regarding NULL/NOT NULL defaults. However by default a “columnDefinition” attribute on @Column also sets the related @JoinColumn’s columnDefinition. This is necessary to make foreign keys work.

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

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

@OneToOne doc:

@OneToOne doc:

The @OneToOne annotation works almost exactly as the @ManyToOne with one additional option that can be specified. The configuration defaults for @JoinColumn using the target entity table and primary key column names apply here too.

@OneToOne注释几乎与@ManyToOne一样,只能指定一个附加选项。 @JoinColumn的配置默认值使用目标实体表,主键列名也适用于此处。

Required attributes:

必需属性:

targetEntity: FQCN of the referenced target entity. Can be the unqualified class name if both classes are in the same namespace. IMPORTANT: No leading backslash!

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

Optional attributes:

可选属性:

cascade: Cascade Option

级联:级联选项

fetch: One of LAZY or EAGER

获取:LAZY或EAGER之一

orphanRemoval: Boolean that specifies if orphans, inverse OneToOne entities that are not connected to any owning instance, should be removed by Doctrine. Defaults to false.

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

inversedBy: The inversedBy attribute designates the field in the entity that is the inverse side of the relationship.

inversedBy:inversedBy属性指定实体中的场,该场是关系的反面。

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

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

#2


7  

You're using the wrong type of Relation for your problem.

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

What you want is a unidirectional one to one from Usermeta to User.

你想要的是从Usermeta到User的单向一对一。

A bidirectional one to one relationship would mean the following:

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

  1. A user MUST have a Usermeta object.
  2. 用户必须拥有Usermeta对象。
  3. A Usermeta object MUST have a User.
  4. Usermeta对象必须有一个用户。

In your case you're only trying to require the second condition.

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

This does mean that you can only hydrate User from Usermeta and not the other way around.

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

Unfortunately doctrine does not support Zero or One to Many relationships.

不幸的是,学说不支持零或一对多的关系。

#3


0  

I got the error message "spl_object_hash() expects parameter 1 to be object, null given in..." while trying the same thing. I tried to define a bidirectional One to One relationship while the inversed value could be null. This gave the error message. Taking away the inversed side of the relationship solved the problem. It is a pity that Zero or One to One relationships aren't supported.

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

#4


0  

I hope I do not disturb anyone by submitting this very late answer, but here is how I solved this problem:

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

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

I added = null; to the attribute declaration. I hope this is of any help for anyone who reads this.

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

#5


-4  

Reading my own old question is quite fun since I see the problem at first glance now..

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

When it came to a solution I've thought that doctrine can only handle Ids named "id", but ... aduserid is just not marked as ID, it's missing the Id annotation and doctrine cannot use the fields for the join column..

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

Second thing, Zdenek Machek was right: It has to be marked as nullable.

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