Подтвердить что ты не робот

Проблема Symfony2 Doctrine2 с опциональным отношением один к одному

У меня проблема с Doctrine2 в Symfony2 и двумя связанными объектами.

Существует пользовательский объект, который может (не должен) иметь ссылку на usermeta, которая содержит информацию, такую ​​как биография и т.д.

Пользователь usermeta не является обязательным, поскольку пользователь импортируется другой системой, а usermeta - в моем приложении.

Конечно, я хочу сохранить оба вместе, так что сохранение пользователя должно создать или обновить объект usermeta.

Оба соединены столбцом с именем aduserid (одно имя в обеих таблицах).

Я признал, что если usermeta является необязательной ссылкой, то владельцем в этом случае должна быть usermeta, иначе доктрина загружает пользователя и нуждается в объекте 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 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();
    }
...
4b9b3361

Ответ 1

Чтение моего собственного старого вопроса довольно забавно, так как я вижу проблему на первый взгляд сейчас.

Когда дело дошло до решения, я подумал, что доктрина может обрабатывать только идентификаторы с именем "id", но... aduserid просто не помечен как идентификатор, он пропускает аннотацию и доктрину Id, которые не могут использовать поля для соединения столбец.

Во-вторых, Зденек Машек был прав: он должен быть отмечен как обнуляемый.

Ответ 2

Комментарий Zdenek Machek почти правильный. Как вы можете видеть из документации Doctrine2, параметр с нулевым должен быть в аннотации присоединения (@JoinColumn), а не в сопоставлении (@OneToOne).

@JoinColumn doc:

Эта аннотация используется в контексте отношений в поля @ManyToOne, @OneToOne и в контексте @JoinTable, вложенном внутри @ManyToMany. Эта аннотация не требуется. Если его не указано, имя атрибута и referColumnName выведены из имен таблиц и первичных ключей.

Обязательные атрибуты:

name: имя столбца, которое содержит идентификатор внешнего ключа для этого отношения. В контексте @JoinTable он указывает имя столбца в таблице соединений.

referatedColumnName: имя идентификатора первичного ключа, используемого для объединения этого отношения.

Дополнительные атрибуты:

уникальный. Определяет, является ли это отношение эксклюзивным между затронутыми объектами и должно быть принудительно соблюдено на уровне ограничения базы данных. По умолчанию false.

nullable: определить, требуется ли связанная сущность, или если null является допустимым состоянием для отношения. По умолчанию используется значение true.

onDelete: действие Cascade (уровень базы данных)

onUpdate: действие Cascade (уровень базы данных)

columnDefinition: фрагмент DDL SQL, который начинается после имени столбца и определяет полное (не переносное!) определение столбца. Этот атрибут позволяет использовать расширенные функции RMDBS. Использование этого атрибута в @JoinColumn необходимо, если вам нужны несколько разные определения столбцов для объединения столбцов, например, в отношении значений NULL/NOT NULL по умолчанию. Однако по умолчанию атрибут "columnDefinition" на @Column также устанавливает соответствующее значение столбца @JoinColumns 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: атрибут inverseedBy обозначает поле в сущности, которая является обратной стороной отношения.

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

Ответ 3

Вы используете неправильный тип отношений для своей проблемы.

Что вам нужно, это однонаправленный один к одному от Usermeta​​strong > до Пользователь.

Двунаправленное отношение "один к одному" означает следующее:

  • Пользователь ДОЛЖЕН иметь объект Usermeta.
  • Объект Usermeta ДОЛЖЕН иметь пользователя.

В вашем случае вы только пытаетесь потребовать второе условие.

Это означает, что вы можете только увлажнять пользователя из Usermeta, а не наоборот.

К сожалению доктрина не поддерживает отношения нуля или одного ко многим.

Ответ 4

Я получил сообщение об ошибке . Функция spl_object_hash() ожидает, что параметр 1 будет объектом, null указывается в... " при попытке выполнить одно и то же. Я попытался определить двунаправленную связь One to One, в то время как обратное значение могло бы быть null. Это дало сообщение об ошибке. Убрав обратную сторону отношений, проблема решена. Жаль, что отношения Zero or One to One не поддерживаются.

Ответ 5

Надеюсь, я никого не потревожаю, представив этот очень поздний ответ, но вот как я решил эту проблему:

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

Я добавил = null; в объявление атрибута. Я надеюсь, что это поможет любой, кто читает это.