看,我知道你已经理解了怎样用sql查询,也许有时你睡觉时还梦到了他们JOIN,order和子查询。这是不是很傻,但是这是我的经历。但是当你看到Doctrine的时候,这些就完全不同了 ,他们以自己的方式去做JOIN。
但是你知道你可以在Doctrine中写原生的SQL查询吗?是的,你可以选择任何形式的功能。当你感觉Doctrine越来越好,你会在一个地方多次使用。当遇到困难的事情时,他会让事情变得简单。
下面我们将了解这一切。别担心,如果你SQL很好的话,你应该善于在Doctrine中写查询。
查询幸运饼干
我们的这个应用是一个幸运饼干库存系统。是的,这是一种带有预测性质的饼干:他能告诉你你的未来,在一个饼干内有一个字条。
在这里我们的数据中有六种不同的幸运分类。如果你点击任意一个分类,你会看到这个分类下所有的命运并能看到有多少已经打印出来了。
点击每个Fotrune
这个项目是一个小型的Symfony应用- 但Doctrine的东西都会用展现出来。现在我们有两个实体:Category
和FortuneCookie :
1 2 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 |
... class Category { /** * @var integer * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string * * @ORM\Column(name="name", type="string", length=255) */ private $name; /** * @var string * * @ORM\Column(name="iconKey", type="string", length=20) */ private $iconKey; /** * @ORM\OneToMany(targetEntity="FortuneCookie", mappedBy="category") */ private $fortuneCookies; ... } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
... class FortuneCookie { /** * @var integer * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var Category * * @ORM\ManyToOne(targetEntity="Category", inversedBy="fortuneCookies") * @ORM\JoinColumn(nullable=false) */ private $category; /** * @var string * * @ORM\Column(name="fortune", type="string", length=255) */ private $fortune; ... } |
从FortuneCookie到Category有一个ManyToOne的关系映射:
1 2 3 4 5 6 7 8 9 10 11 12 |
class FortuneCookie { ... /** * @var Category * * @ORM\ManyToOne(targetEntity="Category", inversedBy="fortuneCookies") * @ORM\JoinColumn(nullable=false) */ private $category; ... } |
回到主页,我们使用entity manager来查询Category’s repository并调用创建好的findAll函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/** * @Route("/", name="homepage") */ public function homepageAction() { $categoryRepository = $this->getDoctrine() ->getManager() ->getRepository('AppBundle:Category'); $categories = $categoryRepository->findAll(); return $this->render('fortune/homepage.html.twig',[ 'categories' => $categories ]); } |
他返回所有的分类,并且迄今为止,他让我们变得很懒,并且避免我们编写一个自定义的查询。这个模板会遍历他们,并输入。让人吃惊。
Doctrine Query语言(DQL)
是时候写一个查询了!让分类按照字母顺序排序。调用一个findAllOrdered()新方法:
1 2 3 4 5 6 7 8 |
public function homepageAction() { $categoryRepository = $this->getDoctrine() ->getManager() ->getRepository('AppBundle:Category'); $categories = $categoryRepository->findAllOrdered(); ... } |
这个方法要写在 CategoryRepository
类里。因此在你需要去创建一个public function findAllOrdered()。为了看看是否已经起效,用一个die来测试:
1 2 3 4 5 6 7 |
class CategoryRepository extends EntityRepository { public function findAllOrdered() { die('this query will blow your mind...'); } } |
刷新!丑陋的黑字出现了。
OK,下面你需要去写SQL,是MySQL查询。好,但是Doctrine使用一个不同的语言:DQL(Doctrine Query Language)。不用担心,他很接近SQL,很多时候你不会注意到他们的区别。
让我们来看一看DQL:$dql = 'SELECT cat FROM AppBundle\Entity\Category cat';
:
1 2 3 4 5 6 7 8 |
class CategoryRepository extends EntityRepository { public function findAllOrdered() { $dql = 'SELECT cat FROM AppBundle\Entity\Category cat'; ... } } |
这个DQL最大的不同是你用php类来替代了数据表。这就是为什么我们选择了完整的类名实体。Symfony的用户习惯于AppBundle:Category,但它仅仅是一个别名-内部总会返回一个完整的类名。
这个cat部分就好像SQL的别名。并且用你写的别名 SELECT cat 去替代 SELECT *。它将查询每一列。最后,我会告诉你如何查询你想要的字段。
执行DQL
要运行它,我们需要创建一个查询对象。获取EntityManager,调用createQuery(),并传入DQL。我们有了Query对象以后,在掉用他的execute();
1 2 3 4 5 6 7 8 9 |
class CategoryRepository extends EntityRepository { public function findAllOrdered() { $dql = 'SELECT cat FROM AppBundle\Entity\Category cat'; $query = $this->getEntityManager()->createQuery($dql); return $query->execute(); } } |
他将会返回Category对象数组。Doctrie标准的模式就是返回对象。不是一个数组数据。但这是可以改变的。
让我们来查询命运!刷新页面。不错,我们看到了同样的结果-这就是findAll()在背后做的事情。
添加 ORDER BY
添加ORDER BY,就像是SQL。添加ORDER BY,然后追加cat.name DESC;
1 2 3 4 5 6 |
public function findAllOrdered() { $dql = 'SELECT cat FROM AppBundle\Entity\Category cat ORDER BY cat.name DESC'; $query = $this->getEntityManager()->createQuery($dql); return $query->execute(); } |
刷新!分类按照字母排序了!所以这个DQL:您提到的类名,来替代SQL表名。如果你“Google:Doctrine DQL”,你可以找到更多的Doctrine文档。
显示我的SQL
但是最终,Doctrine DQL会返回一个真实的Mysql语句,或者PostgreSQL (无论你用什么引擎)。
我们可以看到SQL吗?当然你作为调试他是很有用的。仅仅使用var_dump
$query->getSQL()
:
1 2 3 4 5 6 7 |
public function findAllOrdered() { $dql = 'SELECT cat FROM AppBundle\Entity\Category cat ORDER BY cat.name DESC'; $query = $this->getEntityManager()->createQuery($dql); var_dump($query->getSQL());die; return $query->execute(); } |
刷新!虽然不是很漂亮,但是他出来了。冷静,最靠谱的SQL居然在幕后。删除该调试代码吧。