Doctrine OneToMany级联持续存在于外键上

时间:2013-10-08 20:22:53

标签: php doctrine-orm one-to-many foreign-key-relationship many-to-one

我遇到OneToMany关系问题。我目前正在开发一个日志分析器,它存储原始日志行以及包含关键字的行中已解析的消息。数据库结构如下所示:

数据库

CREATE TABLE IF NOT EXISTS `keywords` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `row_id` bigint(20) unsigned NOT NULL,
  `type` varchar(50) NOT NULL,
  `value` varchar(128) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `type` (`type`),
  KEY `value` (`value`),
  KEY `FK_keywords_rows` (`row_id`),
  CONSTRAINT `FK_keywords_rows` FOREIGN KEY (`row_id`) REFERENCES `rows` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `messages` (
  `row_id` bigint(20) unsigned NOT NULL,
  `profile_name` varchar(50) NOT NULL,
  `type` varchar(50) NOT NULL,
  `subtype` varchar(50) NOT NULL,
  `time` datetime NOT NULL,
  KEY `FK_messages_rows` (`row_id`),
  KEY `FK_messages_profiles` (`profile_name`),
  CONSTRAINT `FK_messages_profiles` FOREIGN KEY (`profile_name`) REFERENCES `profiles` (`name`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `FK_messages_rows` FOREIGN KEY (`row_id`) REFERENCES `rows` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `profiles` (
  `name` varchar(50) NOT NULL,
  `description` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `rows` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `profile_name` varchar(50) NOT NULL,
  `content` varchar(1024) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_rows_profiles` (`profile_name`),
  CONSTRAINT `FK_rows_profiles` FOREIGN KEY (`profile_name`) REFERENCES `profiles` (`name`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

http://yuml.me/3e8a2413.png

日志分析器可以删除未正确解析的关键字,同时该行保留以进行再通。这就是消息没有自己的主键和关键字引用消息的row_id的原因。 我的实体看起来像这样:

配置文件

/**
 * Class Profile
 * @package Ghopple\Entity
 * @ORM\Entity
 * @ORM\Table(name="profiles")
 */
class Profile
{

    /**
     * @ORM\Id
     * @ORM\Column(name="name", type="string", length=50)
     * @var string
     */
    protected $name;

    /**
     * @ORM\Column(name="description", type="string", length=255)
     * @var string
     */
    protected $description;

    /**
     * @ORM\OneToMany(targetEntity="Row", mappedBy="profile", fetch="LAZY")
     * @var Row[]
     */
    protected $rows;

    /**
     * @ORM\OneToMany(targetEntity="Message", mappedBy="profile", fetch="LAZY")
     * @var Message[]
     */
    protected $messages;

/**
 * Class Row
 * @package Ghopple\Entity
 * @ORM\Entity
 * @ORM\Table(name="rows")
 */
class Row
{

    /**
     *
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(name="id", type="integer")
     * @var integer
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="Profile", inversedBy="rows")
     * @ORM\JoinColumn(name="profile_name", referencedColumnName="name")
     * @var Profile
     */
    protected $profile;

    /**
     * @ORM\Column(name="content", type="string", length=1024)
     * @var string
     */
    protected $content;

    /**
     * @ORM\OneToOne(targetEntity="Message", mappedBy="row")
     * @var Message
     */
    protected $message;

消息

/**
 * Class Message
 * @package Ghopple\Entity
 * @ORM\Entity
 * @ORM\Table(name="messages")
 */
class Message
{

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(name="id", type="integer")
     * @var integer
     */
    protected $id;

    /**
     * @ORM\Column(name="type", type="string", length=50)
     * @var string
     */
    protected $type;

    /**
     * @ORM\Column(name="subtype", type="string", length=50)
     * @var string
     */
    protected $subtype;

    /**
     * @ORM\ManyToOne(targetEntity="Profile", fetch="EAGER")
     * @ORM\JoinColumn(name="profile_name", referencedColumnName="name")
     * @var Profile
     */
    protected $profile;

    /**
     * @ORM\OneToOne(targetEntity="Row", fetch="LAZY", cascade={"persist"})
     * @ORM\JoinColumn(name="row_id", referencedColumnName="id")
     * @var Row
     */
    protected $row;

    /**
     * @ORM\OneToMany(targetEntity="Keyword", mappedBy="message", cascade={"persist"})
     * @var Keyword[]
     */
    protected $keywords;

    /**
     * @ORM\Column(name="time", type="datetime")
     * @var DateTime
     */
    protected $time;

关键字

/**
 * Class Keyword
 * @package Ghopple\Entity
 * @ORM\Entity
 * @ORM\Table(name="keywords")
 */
class Keyword
{

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(name="id", type="integer")
     * @var integer
     */
    protected $id;

    /**
     * @ORM\Column(name="type", type="string", length=50)
     * @var string
     */
    protected $type;

    /**
     * @ORM\ManyToOne(targetEntity="Message", inversedBy="keywords")
     * @ORM\JoinColumn(name="row_id", referencedColumnName="row_id")
     * @var Message
     */
    protected $message;

    /**
     * @ORM\Column(name="value", type="string", length=128)
     * @var string
     */
    protected $value;

这就是我尝试做的事情:

    ....
    $profile = $profileRepository->findOneBy(array('name' => 'ghostpp-01'), array('name' => 'DESC'));

    $row = new Row();
    $row->setContent('content');
    $row->setProfile($profile);

    $message = new Message();
    $message->setType('type');
    $message->setSubtype('subtype');
    $message->setTime(new DateTime());
    $message->setProfile($profile);
    $message->setRow($row);

    $keyword = new Keyword();
    $keyword->setType('keyword');
    $keyword->setValue('value');

    $message->addKeyword($keyword);

    $entityManager->persist($message);
    $entityManager->flush();
    ....

我在关键字insert语句中收到异常消息:

An exception occurred while executing 'INSERT INTO keywords (type, value, row_id) VALUES (?, ?, ?)' with params ["keyword", "value", null]:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'row_id' cannot be null

我在这里和通过互联网阅读了很多条目,这就是为什么我在为邮件添加关键字时添加以下行:

    /**
     * @param Keyword $keyword
     * @return $this
     */
    public function addKeyword(Keyword $keyword)
    {
        if (!$this->keywords->contains($keyword)) {
            $this->keywords->add($keyword);
            $keyword->setMessage($this);
        }
        return $this;
    }

    /**
     * @param Keyword $keyword
     * @return $this
     */
    public function removeKeyword(Keyword $keyword)
    {
        if ($this->keywords->contains($keyword)) {
            $this->keywords->remove($keyword);
            $keyword->unsetMessage();
        }
        return $this;
    }

我从http://www.doctrine-project.org/jira/browse/DDC-2244接受这个,它描述了要解决的同样问题。我将关联设置为message和关键字,应该解决错误,但事实并非如此。 现在我的想法....

编辑:

正如您在日志中看到的,他以正确的顺序创建行,但是在插入后他无法解决row_id:

SELECT t0.name AS name1, t0.description AS description2 FROM profiles t0 WHERE t0.name = ? ORDER BY t0.name DESC LIMIT 1
Params     0 => string(10) "ghostpp-01" 
Types     0 => string(6) "string" 
Time0.011378049850464

"START TRANSACTION"
Params
Types
Time0.00012993812561035

INSERT INTO rows (content, profile_name) VALUES (?, ?)
Params     1 => string(7) "content" 
    2 => string(10) "ghostpp-01" 
Types     1 => string(6) "string" 
    2 => string(6) "string" 
Time0.012298107147217

INSERT INTO messages (type, subtype, time, profile_name, row_id) VALUES (?, ?, ?, ?, ?)
Params     1 => string(4) "type" 
    2 => string(7) "subtype" 
    3 => object(stdClass)#511 (3) { ["__CLASS__"]=> string(8) "DateTime" ["date"]=> string(25) "2013-10-09T06:36:29+02:00" ["timezone"]=> string(12) "Europe/Paris" } 
    4 => string(10) "ghostpp-01" 
    5 => int(30) 
Types     1 => string(6) "string" 
    2 => string(6) "string" 
    3 => string(8) "datetime" 
    4 => string(6) "string" 
    5 => string(7) "integer" 
Time0.00024700164794922

INSERT INTO keywords (type, value, row_id) VALUES (?, ?, ?)
Params     1 => string(7) "keyword" 
    2 => string(5) "value" 
    3 => NULL 
Types     1 => string(6) "string" 
    2 => string(6) "string" 
    3 => NULL 
Time0
SQL "ROLLBACK"

0 个答案:

没有答案