首页  >  文章  >  后端开发  >  如何使用 DoctrineExpression 处理不同数据库引擎上的自定义 S/DQL 查询

如何使用 DoctrineExpression 处理不同数据库引擎上的自定义 S/DQL 查询

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-10-28 08:45:02681浏览

How To Handle Custom S/DQL Queries On Different Database Engine with DoctrineExpression

在构建健壮的 Symfony 项目的过程中,经常会出现这样的情况:简单的实体存储库方法(如 findBy())不再足够。对我来说,这一点已经到来,我开始利用自定义 DQL 查询的强大功能来处理更复杂的数据检索需求。当时,我使用 MySQL 作为我的默认数据库。一切都很完美,直到我将项目容器化并决定切换到 PostgreSQL 以获得性能和功能灵活性。

但是,哦不!我的 DQL 查询立即开始抛出错误?出了什么问题?我的自定义 DQL 语法完美地针对 MySQL 的怪癖和功能而设计,但与 PostgreSQL 不兼容。现在需要在两条具有挑战性的道路之间做出选择:

选项 1:恢复到 MySQL 以保证安全。

但是如果我想与喜欢 PostgreSQL 的开发人员共享该项目怎么办?

选项 2:重写我的 DQL 以支持 PostgreSQL。

但是,如果我稍后需要切换回 MySQL 怎么办?或者如果我使用只支持 MySQL 的工具怎么办?

在这些之间进行选择并不容易——这两种选择都可能将我锁定在单一数据库环境中,从而限制了未来技术选择的灵活性。因此,我决定采取不同的方法并创建一个解决方案,以干净、可重用的方式动态处理特定于数据库的查询。


DoctrineExpression 简介

DoctrineExpression 是一个 PHP 库,旨在在 Symfony 或任何使用 Doctrine 的项目中启用跨平台、与数据库无关的 DQL 和 SQL 查询。使用 DoctrineExpression,您可以为每个数据库平台(MySQL、PostgreSQL、SQLite 等)定义自定义语法,它会根据当前数据库驱动程序选择正确的表达式。它的工作原理如下:

  1. 定义多个表达式:为每个数据库驱动程序编写不同的语法,指定与每个平台的功能和怪癖相匹配的唯一查询。
  2. 自动驱动程序检测:DoctrineExpression 检查正在使用的 Doctrine 平台,然后自动为 MySQL、PostgreSQL 或任何其他支持的数据库应用正确的语法。
  3. 面向未来的灵活性:通过允许您轻松切换数据库,DoctrineExpression 可以保证您的代码面向未来,确保您无需大量重写即可支持多个数据库。

现在,有了 DoctrineExpression,我可以灵活地使用 MySQL 或 PostgreSQL(甚至 SQLite),保持代码干净且可维护。我可以根据项目要求、团队偏好或性能考虑来切换平台,而不必担心重构每个自定义查询。

DoctrineExpression 如何解决这个问题

让我们看一个简单的例子,我们需要检索过去 24 小时内注册的用户。这在 MySQL 和 PostgreSQL 中通常有不同的处理方式。


无教义表达

  1. MySQL:使用 DATE_SUB(NOW(), INTERVAL 1 DAY) 查找过去 24 小时内的记录。
  2. PostgreSQL:对同一查询使用 NOW() - INTERVAL '1 天'。

以下是在没有 DoctrineExpression 的情况下单独编写这些内容的方法:

// MySQL Query
$mysqlQuery = $entityManager->createQuery(
    "SELECT u FROM App\Entity\User u WHERE u.registeredAt > DATE_SUB(NOW(), INTERVAL 1 DAY)"
);

如果你使用 PostgreSQL,你会这样写:

// PostgreSQL Query
$postgresQuery = $entityManager->createQuery(
    "SELECT u FROM App\Entity\User u WHERE u.registeredAt > NOW() - INTERVAL '1 day'"
);

如果切换数据库,就需要修改这段代码,既不方便,又容易出错。


与教义表达

使用 DoctrineExpression,您可以定义两种语法并让库处理其余部分:

use Ucscode\DoctrineExpression\DoctrineExpression;
use Ucscode\DoctrineExpression\DriverEnum;

// Create an expression instance with an EntityManager argument
$expression = new DoctrineExpression($entityManager);

// Registration S/DQL for varying database
$expression
    ->defineQuery(DriverEnum::PDO_MYSQL, function($entityManager) {
        return $entityManager->createQuery(
            "SELECT u FROM App\Entity\User u WHERE u.registeredAt > DATE_SUB(NOW(), INTERVAL 1 DAY)"
        );
    })
    ->defineQuery(DriverEnum::PDO_PGSQL, function($entityManager) {
        return $entityManager->createQuery(
            "SELECT u FROM App\Entity\User u WHERE u.registeredAt > NOW() - INTERVAL '1 day'"
        );
    });

// Fet any of the defined query based on the active doctine driver being used
$query = $expression->getCompatibleResult();

现在,DoctrineExpression 检查正在使用的数据库平台,并动态插入当前环境的正确语法。无论你使用 MySQL 还是 PostgreSQL,它都会选择正确的表达式,让你不必每次切换平台时都修改查询,并且还删除了重复使用 if-else 的样板

综上所述:

DoctrineExpression 允许您使用不同的数据库而无需重写查询,从而节省时间和精力。它在容器化或多环境项目中特别有用,在这些项目中您需要使用自定义语法,但数据库首选项可能会根据部署需求或团队熟悉程度而变化。尝试一下,让我知道它对你有什么作用!

查看 GitHub 上的 DoctrineExpression

编码愉快!

以上是如何使用 DoctrineExpression 处理不同数据库引擎上的自定义 S/DQL 查询的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn