【问题标题】:How to set up entity (doctrine) for database view in Symfony 2如何在 Symfony 2 中为数据库视图设置实体(原则)
【发布时间】:2012-01-12 17:48:50
【问题描述】:

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

【问题讨论】:

    标签: php mysql symfony doctrine-orm


    【解决方案1】:

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

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

    【讨论】:

    • @GusDeCooL,好吧,然后放一个标识符。 ;)
    • 非常非常糟糕的做法。调用学说:schema:update... 并且表将被重写为简单表(不是VIEW)。
    • @user1954544,使用 ORM 生成架构是一种不好的做法。
    • @ElnurAbdurrakhimov 使用和 ORM 生成模式是 Symfony 推荐的做法。由于正在运行的查询的性质,许多视图也没有标识符。
    • @SergeVelikanov,如果你让 ORM 为你生成表,你就有麻烦了。 ;)
    【解决方案2】:

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

    将您的实体标记为只读。

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

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

    【讨论】:

    • 但是如何将它与 ORMPurger 一起使用?它不能删除视图。
    【解决方案3】:

    前面的两个答案都是正确的,但是如果你使用学说迁移工具并做一个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

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

    【讨论】:

    • 但这仅在调用更新时有效,验证显示失败。
    • 你是对的,马库斯,我刚刚尝试过,但它失败了......我想如果你使用验证,你应该将实体添加到排除列表中进行验证(类似于我所做的更新)。这是可能的,但从更新中排除实体已经是一种黑客行为,我认为 symfony 应该为视图实现一些内置功能......
    • 您不能在单独的实体管理器中创建视图吗?这将解决我认为的“模式:更新”问题。
    【解决方案4】:

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

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

    直到这里与上述答案相同。这里需要配置学说不绑定模式;

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

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

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

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

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

    【讨论】:

    • 这至少不适用于学说 2.4。架构更新尝试创建一个表。
    • console d:s:u 仍然想用doctrine/doctrine-migrations-bundle:2.1.2 创建表,但它与迁移工作正常,所以对我来说没问题
    【解决方案5】:

    除了上面的答案,我还混合了一些示例代码来扩展 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);
     }
    }
    

    感谢正确的方法

    【讨论】:

      【解决方案6】:

      除了上面的答案,你必须有你的视图实体和虚拟表的命名策略,例如:view_your_table,然后你必须在doctrine.yaml中添加以下代码,以禁用创建新的迁移文件到视图: schema_filter: ~^(?!view_)~

      【讨论】:

        【解决方案7】:

        由于需要在我的数据库中引入 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 answer 中描述的私有构造函数。然而,这并不能阻止orm:schema-tool:update 基于新实体创建一个表,试图覆盖我们的视图......尽管在生产环境中应该避免使用orm:schema-tool:update 以支持迁移脚本,但出于开发目的,这是非常有用。

        由于schema_filter: ~^(?!view_)~ 似乎都不起作用,也已弃用,我设法在Kamil Adryjanek page 上找到了一个技巧,该技巧提供了将EventListenerSubscriber 添加到实体管理器的选项,这将阻止为我们。矿井实现如下:

        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 的问题,还解决了doctrine/migrations 模块的migrations:diff 的问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-08-16
          • 1970-01-01
          • 1970-01-01
          • 2013-12-13
          • 1970-01-01
          • 1970-01-01
          • 2012-01-19
          • 1970-01-01
          相关资源
          最近更新 更多