如何在 Symfony 2 中为数据库视图设置实体(学说)

问题描述 投票:0回答:7

假设我有一个视图表。我想将数据从它获取到一个实体。我可以(以及如何)创建实体类来执行此操作(不需要保存操作)?我只是想展示它们。

php mysql symfony doctrine-orm
7个回答
48
投票

接受的答案是正确的,但我想提供一些您可能需要考虑的其他建议:

将您的实体标记为只读。

将构造函数设为私有,以便只有 Doctrine 可以创建实例。

/**
 * @ORM\Entity(readOnly=true)
 * @ORM\Table(name="your_view_table")
 */
class YourEntity {
    private function __construct() {}
}

29
投票

查询视图没有什么特别的——它只是一个虚拟表。以这种方式设置您的实体的桌子并享受:

/**
 * @ORM\Entity
 * @ORM\Table(name="your_view_table")
 */
class YourEntity {
    // ...
}

22
投票

除了上述答案之外,如果您使用学说迁移进行架构更新,以下配置也可以完美运行。

/**
 * @ORM\Entity(readOnly=true)
 * @ORM\Table(name="view_table_name")
 */
class YourEntity {
    private function __construct() {}
}

到目前为止,与上面的答案相同。这里需要配置doctrine不绑定schema;

doctrine:
    dbal:
        schema_filter: ~^(?!view_)~

上面的过滤器定义过滤所有以“view_”为前缀的表以及可以使用正则表达式扩展的视图。只需确保您已使用“view_”前缀命名您的视图即可。

但是doctrine:schema:update --dump-sql仍然显示视图,我希望他们也将相同的过滤器集成到模式更新中。

我希望这个解决方案对其他人有帮助。

来源:http://symfony.com/doc/current/bundles/DoctrineMigrationsBundle/index.html#manual-tables


22
投票

前面的两个答案都是正确的,但是如果你使用学说迁移工具并执行

schema:update
,它将失败...

因此,除了将实体标记为只读并将构造函数设为私有(在 Ian Phillips 的回答中进行了解释)之外:

/**
 * @ORM\Entity(readOnly=true)
 * @ORM\Table(name="your_view_table")
 */
class YourEntity {
    private function __construct() {}
}

您需要将架构工具设置为在执行架构时忽略实体:更新...

为此,您只需在捆绑包中创建此命令,并在忽略的实体列表中设置您的实体:

src/Acme/CoreBundle/Command/DoctrineUpdateCommand.php:

<?php

namespace Acme\CoreBundle\Command;

use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Doctrine\ORM\Tools\SchemaTool;

class DoctrineUpdateCommand extends \Doctrine\Bundle\DoctrineBundle\Command\Proxy\UpdateSchemaDoctrineCommand {

  protected $ignoredEntities = array(
      'Acme\CoreBundle\Entity\EntityToIgnore'
  );

  protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas) {

    /** @var $metadata \Doctrine\ORM\Mapping\ClassMetadata[] */
    $newMetadatas = array();
    foreach ($metadatas as $metadata) {
      if (!in_array($metadata->getName(), $this->ignoredEntities)) {
        array_push($newMetadatas, $metadata);
      }
    }

    parent::executeSchemaCommand($input, $output, $schemaTool, $newMetadatas);
  }

}

(归功于 Alexandru Trandafir Catalin:从这里获得:https://stackoverflow.com/a/25948910/1442457

顺便说一句,这是我发现处理教义观点的唯一方法...我知道这是一种解决方法...如果有更好的方法,我持开放态度或建议)


2
投票

除了上述答案之外,您还必须有一个视图实体和虚拟表的命名策略,例如:view_your_table,然后您必须将以下代码添加到doctrine.yaml中,以禁止创建新的迁移文件到看法:

schema_filter: ~^(?!view_)~


1
投票

除了上面的答案之外,我还混合了一些示例代码来扩展 DoctrineUpdateCommand

这是我的 DoctrineUpdateCommand:

class DoctrineUpdateCommand extends UpdateSchemaDoctrineCommand{
   protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas) {
      $container = $this->getApplication()->getKernel()->getContainer();  

     $filterExpr = $container->get('doctrine')->getEntityManager()->getConnection()->getConfiguration()->getFilterSchemaAssetsExpression();
     $emptyFilterExpression = empty($filterExpr);

     /** @var $newMetadatas \Doctrine\ORM\Mapping\ClassMetadata */
     $newMetadatas = array();

     foreach ($metadatas as $metadata) {
        if(($emptyFilterExpression||preg_match($filterExpr, $metadata->getTableName()))){
            array_push($newMetadatas, $metadata);
        }        
     }

     parent::executeSchemaCommand($input, $output, $schemaTool, $newMetadatas);
 }
}

感谢您的正确方法


1
投票

由于需要在我的数据库中引入有关 Zend 实现的视图,所以我花了一天的时间。

正如前面所说,你应该创建一个实体,并且这个实体必须有

Id()
注解:

/**
 * @Doctrine\ORM\Mapping\Table(name="your_view")
 * @Doctrine\ORM\Mapping\Entity(readOnly=true)
 */
class YourViewEntity
{
    /**
     * @var SomeEntityInterface
     * @Doctrine\ORM\Mapping\Id()
     * @Doctrine\ORM\Mapping\OneToOne(targetEntity="SomeMainEntity", fetch="LAZY")
     * @Doctrine\ORM\Mapping\JoinColumn(nullable=false, referencedColumnName="id")
     */
    protected $some;

    /**
     * @var AnotherEntityInterface
     * @Doctrine\ORM\Mapping\ManyToOne(targetEntity="AnotherEntity", fetch="LAZY")
     * @Doctrine\ORM\Mapping\JoinColumn(nullable=false, referencedColumnName="id")
     */
    protected $another;

    // Make the constructor private so that only Doctrine can create instances.
    private function __construct() {}
}

还具有私有构造函数,如Ian Phillips回答中所述。然而,这并不能阻止

orm:schema-tool:update
基于新实体创建一个表,试图覆盖我们的视图...尽管事实上在生产中应该避免使用
orm:schema-tool:update
以支持迁移脚本,但出于开发目的,这非常严重有用。

由于

schema_filter: ~^(?!view_)~
似乎都不起作用,也已弃用,我设法在 Kamil Adryjanek page 上找到了一个技巧,它提供了向实体管理器添加
EventListener
Subscriber
的选项,这将阻止为以下对象创建表我们。我的实现如下:

class SkipAutogenerateTableSubscriber implements EventSubscriber
{
    public const CONFIG_KEY = "skip_autogenerate_entities";

    private $ignoredEntities = [];

    public function __construct($config)
    {
        if (array_key_exists(self::CONFIG_KEY, $config)) {
            $this->ignoredEntities = (array) $config[self::CONFIG_KEY];
        }
    }

    public function getSubscribedEvents()
    {
        return [
            ToolEvents::postGenerateSchema
        ];
    }

    public function postGenerateSchema(GenerateSchemaEventArgs $args)
    {
        $schema = $args->getSchema();
        $em = $args->getEntityManager();

        $ignoredTables = [];
        foreach ($this->ignoredEntities as $entityName) {
            $ignoredTables[] = $em->getClassMetadata($entityName)->getTableName();
        }

        foreach ($schema->getTables() as $table) {

            if (in_array($table->getName(), $ignoredTables)) {
                $schema->dropTable($table->getName());
            }
        }
    }
}

这不仅解决了

orm:schema-tool
的问题,还解决了
migrations:diff
模块的
doctrine/migrations
的问题。

© www.soinside.com 2019 - 2024. All rights reserved.