Doctrine / Symfony3 - 具有特定值的数据库列

时间:2016-10-06 22:45:35

标签: php database-design doctrine-orm symfony

我正在尝试为Symfony应用程序构建一个doctrine数据库,而且我不确定组装模式的正确方法。

从此处开始,我将使用Symfony3教程ProductCategory实体来说明我的困惑:

// src/AppBundle/Entity/Category.php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="category")
 */
class Category
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

}

如何定义type,使其成为少数几个值之一(例如:["car", "bike", "bus"])?

我的第一个想法是在Symfony内部进行验证,这样在推送到数据库之前就会进行检查。

但是,这对我来说感觉有些苛刻,我想知道正确的程序是否会在Doctrine本身内强制实施这种约束。

有人可以说明最佳方法吗?

CategoryProduct之间存在一对多的关系时,我的问题会进一步复杂化,Product本身会有一个type变量。我的问题是Product:type的有效值因Category:type而异,例如:

  • Category:type = "car" -> Product:type = ["BMW" OR "Volvo"]
  • Category:type = "bike" -> Product:type = ["BMX" OR "Mountain Bike"]

这一切都应该使用表单/控制器验证来完成,或者我是否正确,假设它应该在"更低的"水平?

1 个答案:

答案 0 :(得分:1)

我认为您应该创建一个单独的产品类型表来存储类别关系,并且它本身存储在产品中,而不是将类别放在产品中。

所以你会有

 Category 

 Product Type

 Product

产品类型是多对一类,一类可能包含多种产品类型,一种产品是多种产品类型,一种产品类型可能包含多种产品。

  Category Type -> Product Type -> Product

有道理,没有必要在产品中存储类别,因为它是由产品类型及其关系推断出来的。

只是澄清一下,

  Category
  --------
     id                //such as 1
     title             //such as Car
     description

  Product Type
  --------
     id                //such as 1
     category_id       //  id from Category 
     title             //such as BMW
     description


  Product
  --------
     id                //such as 6
     product_type_id   // id from Product Type
     title             //2016  New BMW
     description

然后通过加入你可以做

   Select
       c.title As category, pt.title As type, p.title
   From products As p
   Join product_type As pt
      ON p.product_type_id = pt.id
   Join category As c
      ON p.category_id = c.id
   Where
     p.id = 6

然后应该说

   ['category'=>'Car', 'type' => 'BMW', 'title'=> '2016  New BMW']

现在,如果您希望产品类型属于多个类别,您可以/应该这样做

Category
--------
 id                //such as 1
 title             //such as Car
 description

Category Type   ///Bridge table,  (category_id & type_id are unique togather )
--------             
 id                 // you could leave this id out, but it simplifies some things (see below)
 category_id       //  id from Category 
 type_id           //  id from Type

Type
--------
 id                //such as 1
 title             //such as BMW
 description

Product
--------
 id                //such as 6
 category_type_id   // id from Category Type
 title             //2016  New BMW
 description

它让事情变得更复杂,但是当你拥有像多对多这样复杂的关系船时会发生什么。对于查询,您可以添加

Select
    c.title As category, t.title As type, p.title
From
    products As p
Join
    type As t
    ON p.category_type_id = ct.id
Join
    category_type As pt
    ON t.id = ct.type_id 
Join
    category As c
    ON pt.category_id = c.id
Where
    p.id = 6

当然你可能不想在它们中使用标题,我只是觉得不是特别有创意。在最后一个中,如果您可以使用桥表ID,则可以跳过其中一个表,如果您不需要引用它。因此,如果您只想要类别和产品信息,

Select
    c.title As category, p.title
From
    products As p
Join
    category_type As ct
    ON p.category_type_id = ct.id
Join
    category As c
    ON ct.category_id = c.id
Where
    c.id = 6

此模式基本上类似于Y,其类型和类别位于顶部,产品位于底部,nexus(它们连接的位置)为category_type表。如果你不在那里使用id(在类别类型中)它的衬里,你将无法跳过其中一个表(从c到p)。这没关系,因为两个外键(category_id和type_id)在组合时应该是唯一的(复合键)。所以就像这样

多对多(1)Y形(不确定技术术语lol)

      Category-> 
                 CategoryType -> Product
      Type ->

多对多(2)衬垫

      Category-> CategoryType -> Type -> Product

所以在第一个(1)中你可以看到你可以像这样离开一边

                 CategoryType -> Product
      Type ->

OR(如上面的查询所示)

      Category-> 
                 CategoryType -> Product

第二个(2)中的Vs

       Category-> CategoryType ->         Product

你会有一个洞,你无法跳跃。从CategoryType到Product,因为没有对Product记录中的Category或Category Type的引用,反之亦然。但缺点是每个产品只能有一个category_type。如果您使用衬垫,每个产品有一种类型。视觉上第二个就像一个漏斗。

在任何情况下,您在类别和类型之间都有多对多,因此您可以拥有许多(产品)类型的许多类别。例如,您可能有

的产品类型
       Clothes -> Adidas
       Footwear -> Adidas
       Clothes -> Levis

因此,阿迪达斯的记录(类型)属于衣服和鞋类(类别),但衣服也有其他类型,如李维斯。所以它是多对多,这有点难以处理,但它可能更接近你需要的东西,这就是为什么我想尽可能地解释它。

我想在夏季有许多方法可以做到这一点,你只需要事先考虑一下这种关系是什么以及你需要它的灵活性。我要做的最后一件事是我称之为标签。

  Tag
  --------
     id                //such as 1
     title             //such as Car
     description

  Product Tags
  --------
     tag_id          //  id from Tag
     product_id      // id from Product

  Product
  --------
     id                //such as 6
     product_type_id   // id from Product Type
     title             //2016  New BMW
     description

这里我们在产品和标签之间有多对多,因此您可以根据需要在尽可能多的产品上放置尽可能多的标签。但是你失去了阿迪达斯的结构,一直是Footware,或者衣服。

"终极"将是所有三个部分之间的桥牌表。

   Category -> ( bridge ) -> Type -> ( bridge ) -> product.

这变得非常复杂,但你可能有2对多关系,因此产品可能属于许多类型,可能属于许多类别。就个人而言,我会选择标签,它几乎同样灵活,易于处理。创建产品时需要更多选择。