我正在尝试为Symfony应用程序构建一个doctrine数据库,而且我不确定组装模式的正确方法。
从此处开始,我将使用Symfony3教程Product
和Category
实体来说明我的困惑:
// 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本身内强制实施这种约束。
有人可以说明最佳方法吗?
当Category
和Product
之间存在一对多的关系时,我的问题会进一步复杂化,Product
本身会有一个type
变量。我的问题是Product:type
的有效值因Category:type
而异,例如:
Category:type = "car" -> Product:type = ["BMW" OR "Volvo"]
Category:type = "bike" -> Product:type = ["BMX" OR "Mountain Bike"]
这一切都应该使用表单/控制器验证来完成,或者我是否正确,假设它应该在"更低的"水平?
答案 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对多关系,因此产品可能属于许多类型,可能属于许多类别。就个人而言,我会选择标签,它几乎同样灵活,易于处理。创建产品时需要更多选择。