如何在没有连接列的情况下映射一对一关系(实体通过它们的 ID 连接)?

Posted

技术标签:

【中文标题】如何在没有连接列的情况下映射一对一关系(实体通过它们的 ID 连接)?【英文标题】:How to map one-to-one relation without join column (entities are joined via their IDs)? 【发布时间】:2019-12-31 10:45:50 【问题描述】:

在我的工作中,我正在尝试将遗留数据库方案与 Doctrine 进行映射。我无法更改此方案,因为它已被其他公司应用程序使用。以下是简要的方案概述:

表 - global_register_item

ID | NAME                                      | DTYPE
1  | "global register item with article #1"    | law_regulation
2  | "global register item without article #1" | financial_reporter
3  | "global register item without article #2" | law_regulation
4  | "global register item without article #3" | law_regulation
5  | "global register item with article #2"    | financial_reporter

表格 - 文章

ID | SID | other fields which I actually do not need
1  | 89  | ...
5  | 45  | ...

表格 - law_regulation

ID | other fields
1  | ...
3  | ...
4  | ...

表格 - 财务报告者

ID | other fields
2  | ...
5  | ...

所以 global_register_item 是父表,law_regulationfinancial_reporter 继承自该表。为了解决这个问题,我使用了class table inheritance,它工作正常。

问题在于 global_register_itemarticle 之间的关系。它是一对一的关系,通过它们的 ID 列进行连接(如果 global_register_item 中有与 article 相关的记录,则 中有记录>article 表具有相同的 ID)。但是global_register_item中的一些记录在article中没有记录。有什么办法可以将这种关系与 Doctrine 映射起来?

编辑 1

这是我在项目中的 php 代码。顺便提一句。我只需要阅读记录。而且我需要将有关 SID 列的信息发送到我的 GlobalRegisterItem 实体。

类 GlobalRegisterItem

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="global_register_item")
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="DTYPE", type="string")
 * @ORM\DiscriminatorMap(
 *     "law_regulation" = "App\Entity\LawRegulation",
 *     "financial_reporter" = "App\Entity\FinancialReporter")
 */
abstract class GlobalRegisterItem

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

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

     /**
      * Article|null
      * HOW TO MAP THIS?
      */
     private $article;

课堂文章

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="article")
 */
class Article

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

    /**
     * @var int
     * @ORM\Column(name="SID", type="int")
     */
     private $sid;

集体法规定

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="law_regulation")
 */
class LawRegulation extends GlobalRegisterItem

    /** SOME MAPPED FIELDS */

类财务报告员

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="law_regulation")
 */
class FinancialReporter extends GlobalRegisterItem

    /** SOME MAPPED FIELDS */

【问题讨论】:

具体的问题是什么? DTYPE 列有时是 null 有时是 "article" 但您仍想将其用作鉴别器列吗?我理解正确吗?请解释一下“global_register_item中的一些记录在文章中没有记录”部分。 law_regulationglobal_register_itemarticle 之间的关系究竟存储在哪一列?我在您的问题中的任何地方都没有看到加入列。 您是否只是尝试使用new account 编辑您的问题? @NicolaiFröhlich 据我了解,article 只是一个可空的OneToOneglobal_register_item,其中连接列是两个表上的idarticle 的标识符为输入NONE @msg 你对情况的理解是对的。为了更好地解释,我添加了一些代码和“数据”。 【参考方案1】:

您可以在Article 实体中使用OneToOne bidirectional relation:

/**
 * @ORM\OneToOne(targetEntity="GlobalRegisterItem", inversedBy="article")
 * @ORM\JoinColumn(name="id", referencedColumnName="id", nullable=true)
 */
private $item;

并在您的 GlobalRegisterItem 类中引用它:

 /**
  * Article|null
  * @ORM\OneToOne(targetEntity="Article", mappedBy="item")
  */
 private $article;

 /**
  * Gets the sid of the article (if any).
  * @returns int|null
  */
 public function getArticleSid()
 
   if (null !== $this->article) 
     return $this->article->getSid();
   
   return null;
 

【讨论】:

【参考方案2】:

解决此问题的一种可能方法(如果您只需要读取数据)是:

global_register_itemarticle

创建视图
SELECT global_register_item.*, article.SID AS `SID`
FROM global_register_item
LEFT JOIN article ON global_register_item.id = article.id

ID | NAME                                      | DTYPE              | SID
1  | "global register item with article #1"    | law_regulation     | 89
2  | "global register item without article #1" | financial_reporter | NULL
3  | "global register item without article #2" | law_regulation     | NULL
4  | "global register item without article #3" | law_regulation     | NULL
5  | "global register item with article #2"    | financial_reporter | 45

类 GlobalRegisterItem

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="global_register_item_view")
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="DTYPE", type="string")
 * @ORM\DiscriminatorMap(
 *     "law_regulation" = "App\Entity\LawRegulation",
 *     "financial_reporter" = "App\Entity\FinancialReporter")
 */
abstract class GlobalRegisterItem

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

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

     /**
      * int|null
      * @ORM\Column(name="SID", type="integer")
      */
     private $sid;

我认为这远非最佳,但这是我能想到的最佳解决方案。

【讨论】:

以上是关于如何在没有连接列的情况下映射一对一关系(实体通过它们的 ID 连接)?的主要内容,如果未能解决你的问题,请参考以下文章

使用具有一对多关系的 JPA 映射实体,如何添加连接条件

Hibernate框架学习之注解配置关系映射

JPA PessimisticLockScope.NORMAL并锁定“关系”

关系数据库模式设计 - 如何直接从实体的字段集建模一对一映射

在没有 ORM 的情况下实现实体类之间的关系

JPA 单向一对多关联关系