dsa2c2255888
dsa2c2255888
2014-06-17 09:04

正确的对象实例化/持久性排序和注释

已采纳

My use case is simple. There are two entities: Server and Client. Each Server can have Multiple Clients. This should be pretty simple really...

What I need

I require the following as a result of this:

  • Calling $server->getClients() will return all Client entities associated with that server
  • Calling $client->getServer() will return the Server entity associated with that client

I believe that, according to the documentation, this is a One-To-Many Bidirectional relationship.

A one-to-many association has to be bidirectional, unless you are using an additional join-table. This is necessary, because of the foreign key in a one-to-many association being defined on the “many” side. Doctrine needs a many-to-one association that defines the mapping of this foreign key.

The docs above give a really simple example of Product and Feature entities, which I have attempted to adopt for my Server to Client use case.

The Problem

Firstly, I can't seem to get the annotations right to create a Client entity, assign it to a newly created Server entity, then persist / save them. The Client entity always has null for the server_id attribute. What is the ordering required? Why are my annotations not working?

Secondly, I can't figure out if I need a join table to be able to do $client->getServer() or the other way around: $server->getClients(). Do I need a join table to fulfil the above criteria? I tried to add a join table anyway, but no join table was actually created when running doctrine orm:schema-tool:update.

The Code

Note: I do have Setters / Getters on both ends for Client and Server

/**
 * Class Server
 *
 * @ORM\Table(name="servers")
 * @ORM\Entity(repositoryClass="App\Model\Repository\ServerRepository")
 */
class Server
{
   /**
    * @var integer
    *
    * @ORM\Column(name="id", type="integer", nullable=false)
    * @ORM\Id
    * @ORM\GeneratedValue(strategy="IDENTITY")
    */
    private $id;

   /**
    * @var ArrayCollection
    *
    * @ORM\OneToMany(targetEntity="App\Model\Entity\Client", mappedBy="server", cascade={"persist", "remove"})
    */
    private $clients;
}

/**
 * Class Client
 *
 * @ORM\Table(name="clients")
 * @ORM\Entity(repositoryClass="App\Model\Repository\ClientRepository")
 */
class Client
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

   /**
    * @var Server
    *
    * @ORM\OneToMany(targetEntity="App\Model\Entity\Server", inversedBy="client")
    * @ORM\JoinColumn(name="server_id", referencedColumnName="id")
    */
    private $server;
}

I have tried multiple combinations of creating Client and Server entities, calling $server->addClient(new Client)); etc, persisting both in different orders and more.

What exactly am I doing wrong? Why do I have null? What do I need to fix my annotations and object persistence in order to achieve the methods ::getClients() and ::getServer() being made available to me?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

1条回答

  • dongni3854 dongni3854 7年前

    You need to ensure the mutators (getter and setter) methods are present (afaik, at least in my doctrine version) the getter setter are not generated by doctrine, you need to implement them. And the array collection must be in the contstructor:

    in Server Entity:

    public function __construct() {
        $this->clients = new ArrayCollection();
    }
    
    public function addClient(Client $client) {
        $this->clients->add($client);
        return $this;
    }
    
    public function removeClient(Client $client) {
        if ($this->clients->contains($client)) {
            $this->clients->remove($client);
        }
        return $this;
    }
    
    public function getClients() {
        return $this->clients;
    }
    

    Your entity is looking good (annotations), not sure wether you really need repositoryClass="App\Model\Repository\ClientRepository".

    The order of things is not important as long as you have the entity persisted once. An entity is automatically persisted when fetched by findBy or when added to an already persisted entity. Example:

    $server = $entityManager->getRepository('App\Model\Entity\Server')
                            ->findOneByName('test');
    
    $server->addClient(new Client());
    
    // client and server are now both persisted
    
    $entityManager->flush();
    
    // stuff is now saved in the database
    

    Update:

    Sorry I didn't read that you already have getters and setters.

    When updating the schema, try the following:

    ./doctrine orm:clear-cache:metadata
    ./doctrine orm:schema-tool:update
    ./doctrine orm:generate-proxies
    

    Update:

    Found your error:

    * @ORM\JoinColumn(name="server_id", referencedColumnName="id")
    

    server_id is not present. Server::id is, but not Server::server_id :-)

    Correct:

    * @ORM\JoinColumn(name="id", referencedColumnName="id")
    
    点赞 1 评论 复制链接分享

相关推荐