为多对一关系生成模式

时间:2015-08-28 12:49:04

标签: php symfony doctrine

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

父类:

  @Override
public int getCount() {
    if(messagesItems.size() <= maxRowsShow){
        return messagesItems.size();
    }else{
       offset = messagesItems.size() - maxRowsShow;
        return maxRowsShow;
    }

}


@Override
public View getView(int position, View convertView, ViewGroup parent) {

        position = position + offset;
       ...}

正如您所看到的,它与字段接收者和发件人上的User类有多对一的关系。这个类生成得很好。

我想从Message类扩展的子类:

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
}

这门课有一些问题。它是空的,但我使用doctrine生成了字段和函数:generate:entities SupportMessageBundle。

首先,它生成字段private,并在schema:update I get

    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
}

所以我将所有字段更改为protected并在数据库中生成我的表,但没有发送方和接收方ID。任何想法我怎样才能做到呢?或者为什么我的领域首先是私人的?

请注意,我希望Ticket仍然有Message +的字段,我不希望我的部分邮件成为故障单。

2 个答案:

答案 0 :(得分:1)

这样的事情会做到这一点。但您应该关注@StuBez评论并阅读https://doctrine-orm.readthedocs.org/en/latest/reference/inheritance-mapping.html

这是一个JOINED例子,在某些用例中具有性能影响。

<?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
}

答案 1 :(得分:1)

它总是取决于您想要设计的内容。首先让我们说,发电机不适用于您的建议,所以我建议,在这种情况下不使用它。

我改变了一些事情:

  • 我在命名空间Acme下使用两个捆绑包PrivateMessageBundle和PrivateTicketBundle
  • 由于symfony代码风格,我将属性$ is_spam和$ seen_at更改为$ isSeen和$ seenAt

继承映射

正确的类定义,如果要使用继承映射:

<?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的表的表(它将始终与消息表中的相应id相同)和额外的字段状态。

具有相同列的两个表

这也可以使用特征: 消息实体:

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

请注意,在特征中没有关于ORM的任何使用声明。

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();搜索门票,你会发现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')