通过公共表以正确的方式建立关系

时间:2016-11-29 20:46:32

标签: mysql doctrine-orm relational-database

我在数据库中有三个表:interestsubscriptionsubscriber。架构如下所示:

Subscribr Database schema

订阅表对兴趣和订阅者都有一对多的关系。我希望它如何工作,我不确定我是否希望它如何工作以及它实际上如何工作正在排队,但它应该是这样的:订阅者可以有多个兴趣,每个兴趣可以有多个订阅者。这将允许我查看订户具有哪些兴趣以及订阅了哪些兴趣。然后,订阅只涉及一个订阅者和一个兴趣。我认为这是如何设置的,但我只是做了一些测试查询订阅表,我得到了回复:

C:\xampp\htdocs\www\public_html\playground\subscribr>php list_subscriptions.php
-testemail@tester.com
--Magazine
-testemail@tester.com
--Newsletter
-testemail@tester.com
--Promotions
-testemail@tester.com
--Email
-testemail2@tester.com
--Magazine
-testemail2@tester.com
--Promotions
-testemail3@tester.com
--Newsletter
-testemail3@tester.com
--Email
-testemail4@tester.com
--Magazine
-testemail4@tester.com
--Promotions
-testemail4@tester.com
--Email
-testemail5@tester.com
--Magazine
-testemail6@tester.com
--Newsletter
-testemail7@tester.com
--Promotions
-testemail9@tester.com
--Promotions
-testemail10@tester.com
--Newsletter 

我想我的结果更像是这样:

C:\xampp\htdocs\www\public_html\playground\subscribr>php list_subscriptions.php
-testemail@tester.com
--Magazine
--Newsletter
--Promotions
--Email
-testemail2@tester.com
--Magazine
--Promotions
-testemail3@tester.com
--Newsletter
--Email
-testemail4@tester.com
--Magazine
--Promotions
--Email
-testemail5@tester.com
--Magazine
-testemail6@tester.com
--Newsletter
-testemail7@tester.com
--Promotions
-testemail9@tester.com
--Promotions
-testemail10@tester.com
--Newsletter

如果我通过订阅者查询并获取他们的兴趣(通过订阅表),我确实得到了这个结果。我正在使用ORM,因此执行此操作的代码如下所示:

$subscriberRepo = $entityManager->getRepository( 'Subscribr\Entity\Subscriber' );
$subscribers = $subscriberRepo->findAll();

foreach ($subscribers as $subscriber) {
    echo sprintf( "-%s\n", $subscriber->getEmail() );
    foreach ($subscriber->getInterests() as $interest) {
        echo sprintf( "--%s\n", $interest->getInterest()->getName() );
    }
}

因此,我可以使用此架构获得订阅者的订阅和订阅的兴趣,但是在保留订阅表方面是否有意义?或者整件事需要重新设计才能做我想做的事情吗?我喜欢在订阅者和兴趣之间建立间接关系,因为我想在订阅表中添加额外的列,例如从订阅者表中删除is_subscribed并在订阅中添加名为subscription_status的列,这样这个解决方案感觉最干净。但是,它几乎感觉就像一个带有额外字段的连接表。想法?

1 个答案:

答案 0 :(得分:1)

根据您的解释,您可以正确理解您需要映射的内容。以简化的方式,您有两个选择:

选项1

Subscriber 1 - > n Subscription
Subscription n< - 1 Interest

间接表示:Subscriber n - > n Interest
看不到?让代码更好看:

foreach ($subscribers as $subscriber) {
   echo sprintf( "-%s\n", $subscriber->getEmail() );
   foreach ($subscriber->getSubscriptions() as $subscription) {
      echo sprintf( "--%s\n", $subscription->getInterest()->getName() );
   }
}

修改

以上代码适用于映射中的以下更改。此代码说明:迭代订阅者,其中每个订阅者都有一个订阅列表,每个订阅都会引起兴趣。

<强> Subscriber.php

 /**
  * @var array
  * 
  * @ORM\OneToMany(targetEntity="Subscription", mappedBy="subscriber",    cascade={"persist", "remove"}, orphanRemoval=TRUE)
  */
  private $subscriptions;

您应该从private $interests;移除Subscriber。它不会直接访问Interest

<强> Subscription.php

/**
 * @var Interest
 *
 * @ORM\ManyToOne(targetEntity="Interest", inversedBy="subscribers")
 * @ORM\JoinColumn(name="interest_id", referencedColumnName="id", nullable=FALSE)
 */
private $interest;

请注意,每个Subscription都会访问一个Interest

在您的情况下,第一个选项是最好的。

选项2

您可以删除Subscription类并将其表用作参考表。并直接映射:Subscriber n - &gt; n Interest

class Subscriber {

     /**
      * @var array
      * 
      * @ORM\ManyToMany(targetEntity="Interest", cascade={"persist", "remove"}, orphanRemoval=TRUE)
      * @ORM\JoinTable(name="subscription",
      *      joinColumns={@ORM\JoinColumn(name="subscriber_id", referencedColumnName="id")},
      *      inverseJoinColumns={@ORM\JoinColumn(name="interest_id", referencedColumnName="id")}
      *      )
      */
      private $interests;
}

此选项中的问题是您无法使用subscription.interest_date'因为subscription表现在只是一个关系表。关于this question中的更多解释。