如何处理教义协会/关系

编辑本页

警告:您正在浏览的文档欧宝官网下载appob娱乐下载Symfony 2.7,现已不再维护。

本页的更新版本用于Syob娱乐下载mfony 6.2(当前稳定版本)。

如何处理教义协会/关系

假设应用程序中的每个产品都只属于一个类别。在这种情况下,你需要一个类别类,以及一种关联产品对象的类别对象。

首先创建类别实体。因为您知道您最终需要通过Doctrine持久化类别对象,所以您可以让Doctrine为您创建类。

1 2 3
PHP应用程序/控制台原则:生成:实体——无交互\——实体=“AppBundle:类别”\——字段=“名字:字符串(255)”

此命令生成类别实体为你,用一个id场,的名字字段和相关的getter和setter函数。

关系映射元数据

在本例中,每个类别都可以与许多产品,而每个产品只能与一个类别。这种关系可以概括为:许多产品一个类别(或等价地,一个类别许多产品)。

从这个角度来看产品实体,这是一个多对一关系。从这个角度来看类别实体,这是一个一对多的关系。这很重要,因为关系的相对性质决定了使用哪个映射元数据。它还决定了哪个类必须持有对另一个类的引用。

联系产品而且类别实体,只需创建一个类别的属性产品类,注释如下:

  • 注释
  • YAML
  • XML
12 3 4 5 6 7 8 9 10 11 12 13
/ / src / AppBundle /实体/ Product.php/ /……产品/ /……/ * * *@ORM\ManyToOne(targetEntity="Category", inversedBy="products") *@ORM\JoinColumn(name="category_id", referencedColumnName="id") */私人类别;}

这种多对一映射非常关键。它告诉教义使用category_id添加列关于产品表中关联该表中的每个记录与类别表格

接下来,自单类别对象会涉及到很多产品对象,产品属性可以添加到类别类来保存这些关联对象。

  • 注释
  • YAML
  • XML
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/ / src / AppBundle /实体/ Category.php/ /……使用学说常见的集合ArrayCollection类别/ /……/ * * *@ORM\OneToMany(targetEntity="Product", mappedBy="category") */私人产品公共函数__construct()->产品=ArrayCollection ();}}

虽然前面显示的多对一映射是强制性的,但这个一对多映射是可选的。这里包含它是为了帮助演示Doctrine的关系管理功能范围。另外,在这个应用程序的上下文中,这可能对每个人都很方便类别对象自动拥有与其相关的集合产品对象。

请注意

构造函数中的代码很重要。而不是被实例化为传统的数组,美元的产品属性必须是实现Doctrine的类型集合接口。在这种情况下,anArrayCollection对象。这个物体的样子和作用几乎是一样的完全类似于数组,但有一些额外的灵活性。如果这让你不舒服,别担心。想象一下这是一个数组你的身材会很好。

另请参阅

要理解inversedBy而且的mappedBy用法,见教义协会更新欧宝官网下载app文档。

提示

上面使用的元数据中的targetEntity值可以引用具有有效名称空间的任何实体,而不仅仅是同一名称空间中定义的实体。要关联到不同类或包中定义的实体,请输入完整的名称空间作为targetEntity。

现在,您已经向两个产品而且类别类,您必须手动或使用您自己的IDE生成缺少的getter和setter方法。

暂时忽略Doctrine元数据。你现在有两个类产品而且类别,具有自然的多对一关系。的产品类持有一个类别对象,而类别类持有一个集合产品对象。换句话说,您已经以对应用程序有意义的方式构建了类。数据需要持久化到数据库始终是次要的。

现在,回顾上面的元数据产品实体的美元的类别财产。它告诉Doctrine相关的类是类别,而且id的相关类别记录应存储在一个category_id添加字段上的产品表格

换句话说,是相关的类别对象将存储在美元的类别属性,但在幕后,Doctrine将通过将类别的id存储在category_id添加的列产品表格

上面的元数据类别实体的美元的产品财产没有那么复杂。它只是告诉教义去看Product.category属性来确定如何映射关系。

在继续之前,请务必告诉Doctrine添加新的类别表,新product.category_id列和新的外键:

1
PHP应用程序/控制台原则:schema:update——force

现在您可以看到这个新代码的实际运行!假设你在一个控制器中:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/ /……使用AppBundle实体类别使用AppBundle实体产品使用ob娱乐下载组件HttpFoundation响应DefaultController扩展控制器公共函数createProductAction()类别类别();类别->setName (“电脑外围设备”);产品产品();产品->setName (“键盘”);产品->setPrice (19.99);产品->setDescription (“符合人体工学,时尚!”);//将该产品与类别联系起来产品->setCategory (类别);entityManager->getDoctrine ()->getManager ();entityManager->persist (类别);entityManager->persist (产品);entityManager->冲洗();返回响应('保存id为'的新产品产品->getId()。'和新类别id: '类别->getId ());}}

现在,一行被添加到两个类别而且产品表。的product.category_id新产品的列设置为id属于新类别。教条为你管理这种关系的持久性。

当您需要获取关联对象时,您的工作流看起来就像以前一样。首先,获取美元的产品对象,然后访问其相关类别对象:

12 3 4 5 6 7 8 9 10 11 12 13
使用AppBundle实体产品/ /……公共函数showActionproductId产品->getDoctrine ()->getRepository(产品::类)->找到(productId);categoryName产品->getCategory ()->getName ();/ /……

在本例中,首先查询a产品对象基于产品的id.的查询只是该产品的数据和补水美元的产品对象使用该数据。等会儿,等你打电话的时候产品- > getCategory()——> getName (),教义默默地进行第二次查询,以找到类别这和这个有关产品.它准备美元的类别对象并将它返回给你。

重要的是,您可以很容易地访问产品的相关类别,但直到您请求类别时,类别数据才会实际检索到(即它是“惰性加载”)。

您也可以向其他方向查询:

1 2 3 4 5 6 7 8 9 10
公共函数showProductsAction被标记类别->getDoctrine ()->getRepository(类别::类)->找到(被标记);产品类别->getProducts ();/ /……

在这种情况下,会发生相同的情况:首先查询单个类别对象,然后Doctrine执行第二个查询以检索相关的产品对象,但只有一次/如果你要求他们(即当你调用getProducts ()).的美元的产品Variable是all的数组产品与给定对象相关的对象类别对象通过category_id添加价值。

这种“延迟加载”是可能的,因为在必要时,Doctrine会返回一个“代理”对象来代替真正的对象。再看看上面的例子:

1 2 3 4 5 6 7 8 9
产品->getDoctrine ()->getRepository(产品::类)->找到(productId);类别产品->getCategory ();//打印“代理\AppBundleEntityCategoryProxy”转储(get_class (类别));();

这个代理对象扩展了true类别对象,并且外观和行为与它完全相同。区别在于,通过使用代理对象,Doctrine可以延迟对实数据的查询类别数据,直到你真正需要的数据(例如,直到你调用分类- > getName ()).

代理类由Doctrine生成并存储在缓存目录中。虽然你可能永远都不会注意到你的美元的类别Object实际上是一个代理对象,记住这一点很重要。

在下一节中,当您同时检索产品和类别数据时(通过加入),教义将返回真正的类别对象,因为不需要延迟加载任何东西。

在上面的例子中,进行了两个查询——一个是原始对象(例如a类别)和一个用于相关对象(例如产品对象)。

提示

请记住,您可以通过web调试工具栏查看请求期间进行的所有查询。

当然,如果您事先知道需要访问这两个对象,则可以通过在原始查询中发出连接来避免第二个查询。属性中添加以下方法ProductRepository类:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/ / src / AppBundle /仓库/ ProductRepository.php公共函数findOneByIdJoinedToCategoryproductId查询->getEntityManager ()->createQuery ('SELECT p, c FROM AppBundle:Product p JOIN p.category c WHERE p.id =:id'->setParameter (“id”productId);试一试返回查询->getSingleResult ();}(\ \ ORM \ NoResultException教义异常){返回;}}

现在,你可以在控制器中使用这个方法来查询产品对象及其相关对象类别只有一个问题:

1 2 3 4 5 6 7 8 9 10
公共函数showActionproductId产品->getDoctrine ()->getRepository(产品::类)->findOneByIdJoinedToCategory (productId);类别产品->getCategory ();/ /……

更多有关关联的资料

本节介绍了一种常见的实体关系类型,即一对多关系。有关如何使用其他类型关系(例如,一对一,多对多)的更高级细节和示例,请参阅Doctrine关联映射文档欧宝官网下载app

请注意

如果使用注释,则需要在所有注释前加上@ORM \(如。@ORM \ OneToMany),并没有反映在Doctrine的文档中。欧宝官网下载app您还需要包括使用Doctrine\ORM\Mapping作为ORM;声明,进口ORM注释前缀。

此工作,包括代码示例,是根据创作共用BY-SA 3.0许可证。