1
votes

Utilisation de la valeur générée de l'entité parente

J'ai deux entités dans notre projet utilisant Doctrine:

$user = new User();
$user->setUsername('test');
$user->setEmail('test@example.com');
$user->setPassword(password_hash('password', PASSWORD_BCRYPT));

$em->persist($user);
$em->flush();

$userProfile = new UserProfile();
$userProfile->setFirstName('test');
$userProfile->setLastName('user');

$user->setProfile($userProfile);

$em->persist($user);
$em->flush();

Et j'essaye de générer de nouvelles lignes dans la base de données en utilisant quelque chose comme:

class User
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    private $user_id;

    /**
     * @ORM\Column(type="string")
     */
    private $username;

    /**
     * @ORM\Column(type="string")
     */
    private $password;

    /**
     * @ORM\OneToOne(targetEntity="UserProfile", cascade={"persist", "remove"})
     * @ORM\JoinColumn(name="user_id", referencedColumnName="user_id", unique=true)
     * @var UserProfile
     */
    private $profile;

    //...
}

class UserProfile
{
    /**
     * @ORM\Id
     * @ORM\OneToOne(targetEntity="User")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
     */
    private $user;

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     */
    private $user_id;

    /**
     * @ORM\Column(type="string")
     */
    private $first_name = '';

    /**
     * @ORM\Column(type="string")
     */
     private $last_name = '';

     //...
}


2 commentaires

Pouvez-vous poster le code de la fonction User :: setProfile () ?


Ce n'est rien de spécial: public function setProfile (UserProfile $ profile): self {$ this-> profile = $ profile; retourne $ this; }


3 Réponses :


1
votes

La relation entre les entités User et UserProfile est conservée sur la propriété UserProfile :: user , cependant, lorsque vous appelez User :: setProfile () , vous ne définissez pas cette propriété.

Modifiez votre fonction User :: setProfile () comme suit:

function setProfile(UserProfile $profile): self
{
    $profile->setUser($this);
    $this->profile = $profile;

    return $this;
}


7 commentaires

Merci pour la suggestion, mais cela entraîne une erreur similaire, bien que maintenant il se plaint: UserProfile n'a pas d'ID attribué pour le champ 'user_id'. La stratégie de génération d'identifiant pour cette entité nécessite que le champ ID soit rempli avant que EntityManager # persist () soit appelé. Si vous souhaitez plutôt des identificateurs générés automatiquement, vous devez ajuster le mappage des métadonnées en conséquence. dans /home/ddc/vendor/doctrine/orm/lib/Doctrine/ORM/ORMException.‌ php en ligne 87


Dans votre code, vous appelez $ em-> persist ($ user); deux fois, plutôt que $ em-> persist ($ userProfile);


Le changer en $ em-> persist ($ userProfile); ne change pas l'erreur. L'association doit de toute façon cascade de user -> userProfile.


Avez-vous validé vos relations?


Je viens de lancer orm: validate-schema et je me suis plaint d'avoir le champ $ user dans UserProfile comme id. J'ai supprimé cela et l'outil validé. La même erreur se produit cependant.


Avez-vous une colonne ID sur votre entité UserProfile ? Pouvez-vous publier votre code mis à jour? Parce que les annotations sur les propriétés $ user_id et $ user semblent incorrectes. Ils ont des annotations @ORM \ Id , ce qui est faux.


J'ai supprimé @ORM \ Id de la propriété $ user . Je n'ai pas de colonne d'identifiant distincte sur cette table, juste un index unique sur la colonne user_id .



1
votes

Votre mappage n'est pas valide. Validez votre schéma - il manque mappedBy et inversedBy . Lorsque vous corrigez le mappage, cela fonctionnera comme prévu.

Validation du schéma dans Symfony:

php public/index.php orm:schema-tool:validate

Dans ZF:

bin/console doc:sch:val


2 commentaires

./vendor/bin/doctrine orm: validate-schema dit que c'est correct (je n'utilise pas de framework). De plus, l'exemple sur le site de doctrine ne mentionne pas mappedBy ou inversedBy. J'ai essayé de les ajouter auparavant, mais cela n'a pas aidé.


Il y a de toute façon quelque chose qui ne va pas avec votre schéma. Pourquoi avez-vous besoin de cette propriété $ user_id dans les deux entités, dans le cadre de Id lol? Cela n'a aucun sens. Conservez uniquement le $ profile dans l'entité User , le $ user dans l'entité UserProfile et liez-les ensemble en utilisant inversedBy sur l'utilisateur et mappedBy sur le profil. Supprimez la propriété $ user_id inutile des deux entités. Vous n'avez pas non plus besoin du paramètre "unique" lorsque vous utilisez les relations OneToOne car il est défini par défaut. Corrigez votre cartographie, mettez à jour votre question puis nous pouvons continuer. Ne pensez pas à la base de données, concentrez-vous sur le modèle



0
votes

Grâce à @emix et @fubar, les deux ont contribué à la solution. C'est ce qui a fonctionné à la fin:

class User
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $user_id;

    /**
     * @ORM\Column(type="string")
     */
    private $username;

    /**
     * @ORM\Column(type="string")
     */
    private $password;

    /**
     * @ORM\OneToOne(targetEntity="UserProfile", mappedBy="user", cascade={"persist", "remove"})
     * @var UserProfile
     */
    private $profile;

    //...

    public function setProfile(UserProfile $profile) : self
    {
        $profile->setUser($this);

        $this->profile = $profile;

        return $this;
    }
}

class UserProfile
{
    /**
     * @ORM\Id
     * @ORM\OneToOne(targetEntity="User", inversedBy="profile")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
     */
    private $user;

    /**
     * @ORM\Column(type="string")
     */
    private $first_name = '';

    /**
     * @ORM\Column(type="string")
     */
     private $last_name = '';

     //...
}

Ce qui impliquait de supprimer $ user_id de l'entité UserProfile et d'ajouter un paramètre inversedBy au OneToOne .

Suppression de JoinColumn de l'entité User et correction du setter pour setProfile () afin qu'il définit $ user sur l'entité UserProfile.


0 commentaires