我可以在不将实体连接到数据库表的情况下使用 ORM

Posted

技术标签:

【中文标题】我可以在不将实体连接到数据库表的情况下使用 ORM【英文标题】:Can I use ORM without connecting entity to a database table 【发布时间】:2015-07-14 09:56:46 【问题描述】:

我有一个从 REST Web 服务中提取数据的实体。为了与我的应用程序中从数据库中提取数据的实体保持一致,我使用了 ORM 并覆盖了存储库中的查找函数。

我的问题是 ORM 似乎需要一个数据库表。当我运行doctrine:schema:update 时,它抱怨需要实体的索引,然后当我添加一个索引时,它会为实体创建一个表。我想这将是未来的一个问题,因为 ORM 将要查询数据库而不是 Web 服务。

那么……我做错了吗?

1,如果我继续使用 ORM,我怎样才能让它不再需要单个实体的数据库表。

2,如果我忘记了 ORM,我应该把我的数据加载函数放在哪里?我可以在不使用 ORM 的情况下将实体连接到存储库吗?

【问题讨论】:

【参考方案1】:

那么……我做错了吗?

是的。如果您真的不想使用 ORM,那么使用 ORM 接口是没有意义的。

我认为最好的方法是根本不考虑实现细节。为存储库引入您自己的接口:

interface Products

    /**
     * @param string $slug
     *
     * @return Product[]
     */
    public function findBySlug($slug);


interface Orders

    /**
     * @param Product $product
     * 
     * @return Order[]
     */
    public function findProductOrders(Product $product);

并使用 ORM 实现它们:

class DoctrineProducts implements Products

    private $em;

    public function __construct(EntityManager $em)
    
        $this->em = $em;
    

    public function findBySlug($slug)
    
        return $this->em->createQueryBuilder()
           ->select()
           // ...
    

或 Rest 客户端:

class RestOrders implements Orders

    private $httpClient;

    public function __construct(HttpClient $httpClient)
    
        $this->httpClient = $httpClient;
    

    public function findProductOrders(Product $product)
    
        $orders = $this->httpClient->get(sprintf('/product/%d/orders', $product->getId()));

        $orders = $this->hydrateResponseToOrdersInSomeWay($orders);

        return $orders;
    

您甚至可以让一些方法使用 http 客户端,而另一些则使用单个存储库中的数据库。

将您的存储库注册为服务并使用它们,而不是直接调用Doctrine::getRepository()

services:
    repository.orders:
        class: DoctrineOrders
        arguments:
            - @doctrine.orm.entity_manager

始终依赖于您的存储库接口,而不是特定的实现。换句话说,始终使用存储库接口类型提示:

class DefaultController

    private $orders;

    public function __construct(Orders $orders)
    
        $this->orders = $orders;
    

    public function indexAction(Product $product)
    
        $orders = $this->orders->findProductOrders($product);

        // ...
    

如果您不将控制器注册为服务:

class DefaultController extends Controller

    public function indexAction(Product $product)
    
        $orders = $this->get('repository.orders')->findProductOrders($product);

        // ...
    

这种方法的一个巨大优势是您可以随时更改实现细节。 mysql 搜索不够好?让我们使用弹性搜索,它只是一个存储库!

如果您需要调用 $product->getOrders() 并在后台从 API 获取订单,在学说的延迟加载和事件侦听器的帮助下应该仍然可以。

【讨论】:

因此工作的 MVC,RestOrders 和 DoctrineProducts 类是存储库,与我已经编写的用于覆盖 ORM 函数的存储库相同。我只需要根据需要包含并创建它们,而不是使用 $em->getRepository() 函数来加载它们。 Order 实体不需要知道它是由 RestOrders 存储库管理的。对吗? 是的,将您的存储库注册为服务并使用它们而不是 Doctrine::getRepository()。如果需要,您仍然可以扩展学说的实体存储库基类,在这种情况下,您需要将它们注册为由工厂创建(学说将是工厂)。或者您可以执行我在答案中提出的操作,仅将实体管理器注入您的存储库。

以上是关于我可以在不将实体连接到数据库表的情况下使用 ORM的主要内容,如果未能解决你的问题,请参考以下文章

如何在不将实例模型添加到数据库的情况下向实体模型添加FK约束?

NestJS + MySQL:如何在不设置实体的情况下连接多个数据库

如何在不连接到开放式办公室的情况下查看 .odb 数据库文件的内部?

我可以在不使用 websockets 的情况下使用本机 mqtt 连接到我的 mqtt 代理吗?

在不重载的情况下将 JSON api 连接到 tableView

在不设置 SRV 记录的情况下连接到 Google 帐户