为多对一关系生成模式


Generating schema for many to one relation

我有一个Message类,并且希望扩展一个Ticket类,它将成为某种支持票据类,因此它们可能有另一个名为'status'的字段。

父类:

namespace PrivateMessageBundle'Entity; 
use Doctrine'ORM'Mapping as ORM;
use MedApp'CrudBundle'Entity'User;
/**
 * Message
 *
 * @ORM'Table()
 * @ORM'Entity
 */
class Message
{
    /**
     * @var integer
     *
     * @ORM'Column(name="id", type="integer")
     * @ORM'Id
     * @ORM'GeneratedValue(strategy="AUTO")
     */
    protected $id;
    /**
     * @var string
     *
     * @ORM'Column(name="title", type="string", length=50)
     */
    protected $title;
    /**
     * @ORM'ManyToOne(targetEntity="MedApp'CrudBundle'Entity'User")
     * @ORM'JoinColumn(referencedColumnName="id")
     */
    protected $receiver;
    /**
     * @ORM'ManyToOne(targetEntity="MedApp'CrudBundle'Entity'User")
     * @ORM'JoinColumn(referencedColumnName="id")
     */
    protected $sender;
    /**
     * @var string
     *
     * @ORM'Column(name="content", type="string", length=2000)
     */
    protected $content;
    /**
     * @var 'DateTime
     *
     * @ORM'Column(name="date", type="datetime")
     */
    protected $date;

    /**
     * @var boolean
     *
     * @ORM'Column(name="is_spam", type="boolean")
     */
    protected $is_spam=false;

    /**
     * @var 'DateTime
     *
     * @ORM'Column(name="seen_at", type="datetime",nullable=true)
     */
    protected $seen_at=null;

//autogenerated functions here
}

可以看到,它与我的User类在字段receiver和sender上有多对一的关系。这个类生成得很好。

我想从Message类扩展的子类:

    namespace SupportMessageBundle'Entity;
use Doctrine'ORM'Mapping as ORM;
use PrivateMessageBundle'Entity'Message;
/**
 * Ticket
 *
 * @ORM'Table()
 * @ORM'Entity
 */
class Ticket extends Message
{
    /**
     * @var integer
     */
    private $id;
    /**
     * @var string
     */
    private $title;
    /**
     * @var string
     */
    private $content;
    /**
     * @var 'DateTime
     */
    private $date;
    /**
     * @var boolean
     */
    private $is_spam;
    /**
     * @var 'DateTime
     */
    private $seen_at;
    /**
     * @var 'MedApp'CrudBundle'Entity'User
     */
    private $receiver;
    /**
     * @var 'MedApp'CrudBundle'Entity'User
     */
    private $sender;
//auto generated functions
}

这个类有几个问题。它是空的,但是我用doctrine:generate:entities SupportMessageBundle生成了字段和函数。

首先,它生成字段private,在schema:update我得到

Compile Error: Access level to SupportMessageBundle'Entity'Ticket::$id must  
   be protected (as in class PrivateMessageBundle'Entity'Message) or weaker 

因此我将所有字段更改为protected,它在数据库中生成我的表,但没有发送方和接收方id。有什么办法能让它也这么做吗?或者为什么我的田地一开始就被设为私有?

注意,我希望Ticket仍然有Message的字段,我不希望我的一些消息是Tickets

这总是取决于你想要设计什么。首先,让我们说,生成器不能为您的提议工作,所以我建议,不要在这种情况下使用它。

Something I changed:

  • 我使用两个bundle PrivateMessageBundle和PrivateTicketBundle都在命名空间Acme
  • 我将属性$is_spam和$seen_at更改为$isSeen和$seenAt,因为symfony代码风格

继承映射如果要使用继承映射,正确的类定义是:
<?php
namespace Acme'PrivateMessageBundle'Entity;
use Doctrine'ORM'Mapping as ORM;
use AppBundle'Entity'User;
/**
 * Message
 *
 * @ORM'Table(name="message")
 * @ORM'Entity()
 * @ORM'InheritanceType("JOINED")
 * @ORM'DiscriminatorColumn(name="discr", type="string")
 * @ORM'DiscriminatorMap({"message"="Message", "ticket" = "Acme'PrivateTicketBundle'Entity'Ticket"})
 *
 */
class Message
{
    /**
     * @var integer
     *
     * @ORM'Column(name="id", type="integer")
     * @ORM'Id
     * @ORM'GeneratedValue(strategy="AUTO")
     */
    protected $id;
    /**
     * @var string
     *
     * @ORM'Column(name="title", type="string", length=50)
     */
    protected $title;
    /**
     * @ORM'ManyToOne(targetEntity="AppBundle'Entity'User")
     * @ORM'JoinColumn(referencedColumnName="id")
     */
    protected $receiver;
    /**
     * @ORM'ManyToOne(targetEntity="AppBundle'Entity'User")
     * @ORM'JoinColumn(referencedColumnName="id")
     */
    protected $sender;
    /**
     * @var string
     *
     * @ORM'Column(name="content", type="string", length=2000)
     */
    protected $content;
    /**
     * @var 'DateTime
     *
     * @ORM'Column(name="date", type="datetime")
     */
    protected $date;

    /**
     * @var boolean
     *
     * @ORM'Column(name="is_spam", type="boolean")
     */
    protected $isSpam = false;

    /**
     * @var 'DateTime
     *
     * @ORM'Column(name="seen_at", type="datetime",nullable=true)
     */
    protected $seenAt = null;
// [...] skip constructor, getter, setter and other methods
 }

Ticket类是这样的

<?php
namespace Acme'PrivateTicketBundle'Entity;
use Acme'PrivateMessageBundle'Entity'Message;
use Doctrine'ORM'Mapping as ORM;
/**
 * Ticket extending Message
 *
 * @ORM'Table(name="ticket")
 * @ORM'Entity()
 */
class Ticket extends Message
{
    /**
     * @var string
     * @ORM'Column(name="status", type="string")
     */
    protected $status;
    /**
     * Set status
     *
     * @param string $status
     * @return Ticket
     */
    public function setStatus($status)
    {
        $this->status = $status;
        return $this;
    }
    /**
     * Get status
     *
     * @return string 
     */
    public function getStatus()
    {
        return $this->status;
    }
}

将生成以下表:

CREATE TABLE message (id INTEGER NOT NULL, receiver_id INTEGER DEFAULT NULL, sender_id INTEGER DEFAULT NULL, title VARCHAR(50) NOT NULL, content VARCHAR(2000) NOT NULL, date DATETIME NOT NULL, is_spam BOOLEAN NOT NULL, seen_at DATETIME DEFAULT NULL, discr VARCHAR(255) NOT NULL, PRIMARY KEY(id));
CREATE TABLE ticket (id INTEGER NOT NULL, status VARCHAR(255) NOT NULL, PRIMARY KEY(id));

一个用于包含为消息定义的所有字段的消息实体,一个用于仅包含和id的ticket表(它将始终与消息表中相应的id相同)和额外的字段状态。

具有相同列的两个表

这也可以使用traits:信息实体:

<?php
namespace Acme'PrivateMessageBundle'Entity;
use Doctrine'ORM'Mapping as ORM;
/**
 * Message
 *
 * @ORM'Table(name="message")
 * @ORM'Entity()
 */
class Message
{
  // Use the MessageTraid
  use MessageTrait;
}

(你必须保留use Doctrine'ORM'Mapping as ORM; !)

票务实体:

<?php
namespace Acme'PrivateTicketBundle'Entity;
use Acme'PrivateMessageBundle'Entity'MessageTrait;
use Doctrine'ORM'Mapping as ORM;
/**
 * Ticket extending Message
 *
 * @ORM'Table(name="ticket")
 * @ORM'Entity()
 */
class Ticket
{
    // Use the MessageTraid
    use MessageTrait;
    /**
     * @var string
     * @ORM'Column(name="status", type="string")
     */
    protected $status;
    /**
     * Set status
     *
     * @param string $status
     * @return Ticket
     */
    public function setStatus($status)
    {
        $this->status = $status;
        return $this;
    }
    /**
     * Get status
     *
     * @return string 
     */
    public function getStatus()
    {
        return $this->status;
    }
}

这是性状:

<?php
namespace Acme'PrivateMessageBundle'Entity;

trait MessageTrait
{
    /**
     * @var integer
     *
     * @ORM'Column(name="id", type="integer")
     * @ORM'Id
     * @ORM'GeneratedValue(strategy="AUTO")
     */
    protected $id;
    /**
     * @var string
     *
     * @ORM'Column(name="title", type="string", length=50)
     */
    protected $title;
    /**
     * @ORM'ManyToOne(targetEntity="AppBundle'Entity'User")
     * @ORM'JoinColumn(referencedColumnName="id")
     */
    protected $receiver;
    /**
     * @ORM'ManyToOne(targetEntity="AppBundle'Entity'User")
     * @ORM'JoinColumn(referencedColumnName="id")
     */
    protected $sender;
    /**
     * @var string
     *
     * @ORM'Column(name="content", type="string", length=2000)
     */
    protected $content;
    /**
     * @var 'DateTime
     *
     * @ORM'Column(name="date", type="datetime")
     */
    protected $date;

    /**
     * @var boolean
     *
     * @ORM'Column(name="is_spam", type="boolean")
     */
    protected $isSpam = false;

    /**
     * @var 'DateTime
     *
     * @ORM'Column(name="seen_at", type="datetime",nullable=true)
     */
    protected $seenAt = null;

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }
    /**
     * Set title
     *
     * @param string $title
     * @return Message
     */
    public function setTitle($title)
    {
        $this->title = $title;
        return $this;
    }
    /**
     * Get title
     *
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }
    /**
     * Set content
     *
     * @param string $content
     * @return Message
     */
    public function setContent($content)
    {
        $this->content = $content;
        return $this;
    }
    /**
     * Get content
     *
     * @return string
     */
    public function getContent()
    {
        return $this->content;
    }
    /**
     * Set date
     *
     * @param 'DateTime $date
     * @return Message
     */
    public function setDate($date)
    {
        $this->date = $date;
        return $this;
    }
    /**
     * Get date
     *
     * @return 'DateTime
     */
    public function getDate()
    {
        return $this->date;
    }
    /**
     * Set isSpam
     *
     * @param boolean $isSpam
     * @return Message
     */
    public function setIsSpam($isSpam)
    {
        $this->isSpam = $isSpam;
        return $this;
    }
    /**
     * Get isSpam
     *
     * @return boolean
     */
    public function getIsSpam()
    {
        return $this->isSpam;
    }
    /**
     * Set seenAt
     *
     * @param 'DateTime $seenAt
     * @return Message
     */
    public function setSeenAt($seenAt)
    {
        $this->seenAt = $seenAt;
        return $this;
    }
    /**
     * Get seenAt
     *
     * @return 'DateTime
     */
    public function getSeenAt()
    {
        return $this->seenAt;
    }
    /**
     * Set receiver
     *
     * @param 'AppBundle'Entity'User $receiver
     * @return Message
     */
    public function setReceiver('AppBundle'Entity'User $receiver = null)
    {
        $this->receiver = $receiver;
        return $this;
    }
    /**
     * Get receiver
     *
     * @return 'AppBundle'Entity'User
     */
    public function getReceiver()
    {
        return $this->receiver;
    }
    /**
     * Set sender
     *
     * @param 'AppBundle'Entity'User $sender
     * @return Message
     */
    public function setSender('AppBundle'Entity'User $sender = null)
    {
        $this->sender = $sender;
        return $this;
    }
    /**
     * Get sender
     *
     * @return 'AppBundle'Entity'User
     */
    public function getSender()
    {
        return $this->sender;
    }
}

注意trait中没有任何关于ORM的use语句

Doctrine将使用在您的类中定义的ODM名称空间。

将生成两个表:

CREATE TABLE message (id INTEGER NOT NULL, receiver_id INTEGER DEFAULT NULL, sender_id INTEGER DEFAULT NULL, title VARCHAR(50) NOT NULL, content VARCHAR(2000) NOT NULL, date DATETIME NOT NULL, is_spam BOOLEAN NOT NULL, seen_at DATETIME DEFAULT NULL, PRIMARY KEY(id));
CREATE TABLE ticket (id INTEGER NOT NULL, receiver_id INTEGER DEFAULT NULL, sender_id INTEGER DEFAULT NULL, status VARCHAR(255) NOT NULL, title VARCHAR(50) NOT NULL, content VARCHAR(2000) NOT NULL, date DATETIME NOT NULL, is_spam BOOLEAN NOT NULL, seen_at DATETIME DEFAULT NULL, PRIMARY KEY(id));

快乐编码

第一个示例的更新

在本例中,如果使用$em->getRepository('AcmePrivateMessageBundle:Message')->findAll();搜索消息,还将获得Ticket实体,因为创建的查询如下所示:

SELECT 
  t0.id AS id2, 
  t0.title AS title3, 
  t0.content AS content4, 
  t0.date AS date5, 
  t0.is_spam AS is_spam6, 
  t0.seen_at AS seen_at7, 
  t0.receiver_id AS receiver_id8, 
  t0.sender_id AS sender_id9, 
  t0.discr, 
  t1.status AS status10 
FROM 
  message t0 
  LEFT JOIN ticket t1 ON t0.id = t1.id

(注意LEFT JOIN)

但是如果你用$entities = $em->getRepository('AcmePrivateTicketBundle:Ticket')->findAll();搜索Tickets,你会发现Ticket只是因为生成的sql看起来有点不同:

SELECT 
  t1.id AS id2, 
  t1.title AS title3, 
  t1.content AS content4, 
  t1.date AS date5, 
  t1.is_spam AS is_spam6, 
  t1.seen_at AS seen_at7, 
  t0.status AS status8, 
  t1.receiver_id AS receiver_id9, 
  t1.sender_id AS sender_id10, 
  t1.discr 
FROM 
  ticket t0 
  INNER JOIN message t1 ON t0.id = t1.id

要获取消息,您必须使用查询生成器:

    $query = $em->createQuery("SELECT message FROM Acme'PrivateMessageBundle'Entity'Message message WHERE message INSTANCE OF Acme'PrivateMessageBundle'Entity'Message");
    $entities = $query->getResult();

这将产生如下查询:

SELECT 
  m0_.id AS id0, 
  m0_.title AS title1, 
  m0_.content AS content2, 
  m0_.date AS date3, 
  m0_.is_spam AS is_spam4, 
  m0_.seen_at AS seen_at5, 
  t1_.status AS status6, 
  m0_.discr AS discr7, 
  m0_.receiver_id AS receiver_id8, 
  m0_.sender_id AS sender_id9 
FROM 
  message m0_ 
  LEFT JOIN ticket t1_ ON m0_.id = t1_.id 
WHERE 
  m0_.discr IN ('message')

这样就可以了。但是你应该关注@StuBez评论并阅读https://doctrine-orm.readthedocs.org/en/latest/reference/inheritance-mapping.html

这是一个在某些用例中对性能有影响的join示例。

<?php
namespace PrivateMessageBundle'Entity;
use Doctrine'ORM'Mapping as ORM;
/**
 * @ORM'Entity
 * @ORM'InheritanceType("JOINED")
 * @ORM'DiscriminatorColumn(name="discr", type="string")
 * @ORM'DiscriminatorMap({"ticket" = "Ticket")
 */
class Message
{
    /**
     * @var integer
     *
     * @ORM'Column(name="id", type="integer")
     * @ORM'Id
     * @ORM'GeneratedValue(strategy="AUTO")
     */
    protected $id;
    /**
     * @var string
     *
     * @ORM'Column(name="title", type="string", length=50)
     */
    protected $title;
    // ...
}
/** @ORM'Entity */
class Ticket extends Message
{
    // ... New fields don't repeat parent one
}