在构建健壮的 Symfony 项目的过程中,经常会出现这样的情况:简单的实体存储库方法(如 findBy())不再足够。对我来说,这一点已经到来,我开始利用自定义 DQL 查询的强大功能来处理更复杂的数据检索需求。当时,我使用 MySQL 作为我的默认数据库。一切都很完美,直到我将项目容器化并决定切换到 PostgreSQL 以获得性能和功能灵活性。
但是,哦不!我的 DQL 查询立即开始抛出错误?出了什么问题?我的自定义 DQL 语法完美地针对 MySQL 的怪癖和功能而设计,但与 PostgreSQL 不兼容。现在需要在两条具有挑战性的道路之间做出选择:
选项 1:恢复到 MySQL 以保证安全。
但是如果我想与喜欢 PostgreSQL 的开发人员共享该项目怎么办?
选项 2:重写我的 DQL 以支持 PostgreSQL。
但是,如果我稍后需要切换回 MySQL 怎么办?或者如果我使用只支持 MySQL 的工具怎么办?
在这些之间进行选择并不容易——这两种选择都可能将我锁定在单一数据库环境中,从而限制了未来技术选择的灵活性。因此,我决定采取不同的方法并创建一个解决方案,以干净、可重用的方式动态处理特定于数据库的查询。
DoctrineExpression 是一个 PHP 库,旨在在 Symfony 或任何使用 Doctrine 的项目中启用跨平台、与数据库无关的 DQL 和 SQL 查询。使用 DoctrineExpression,您可以为每个数据库平台(MySQL、PostgreSQL、SQLite 等)定义自定义语法,它会根据当前数据库驱动程序选择正确的表达式。它的工作原理如下:
现在,有了 DoctrineExpression,我可以灵活地使用 MySQL 或 PostgreSQL(甚至 SQLite),保持代码干净且可维护。我可以根据项目要求、团队偏好或性能考虑来切换平台,而不必担心重构每个自定义查询。
让我们看一个简单的例子,我们需要检索过去 24 小时内注册的用户。这在 MySQL 和 PostgreSQL 中通常有不同的处理方式。
以下是在没有 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中文网其他相关文章!