【问题标题】:Mapping two tables to one entity in Doctrine2在 Doctrine2 中将两个表映射到一个实体
【发布时间】:2011-08-10 02:58:50
【问题描述】:

我正在考虑将教义用于我正在开发的应用程序 - 但在阅读了文档后,我在概念化如何用实体表示我们拥有的数据库结构时遇到了麻烦。

我有许多表,其中包含保存如下翻译数据的合作伙伴表......

我希望有一个实体(导航元素)可以访问“标签”字段,具体取决于我在应用程序中设置的语言。 Doctrine 文档中的以下内容似乎表明您需要定义一个(单个)表,用于持久化实体

http://www.doctrine-project.org/docs/orm/2.0/en/reference/basic-mapping.html 默认情况下,实体将是 持久化到具有相同的表 name 作为类名。为了 改变它,你可以使用@Table 注释如下:

或者我需要定义两个实体并将它们链接起来(或者允许翻译表从元素表继承)。

我将使用什么策略来始终将 language_id 子句插入到 Join 中(以确保我为当前设置的语言提取正确的标签)。这是我要在实体本身或其他地方定义的东西吗?

【问题讨论】:

    标签: orm symfony1 doctrine-orm data-modeling


    【解决方案1】:

    这似乎适合One-To-Many Bidirectional association。这是从该页面翻译成您的情况的场景:

    /** @Entity */
    class NavigationElement
    {
        // ...
        /**
         * @OneToMany(targetEntity="NavigationElementTranslation", mappedBy="navigationElement")
         */
        private $translations;
        // ...
    
        public function __construct() {
            $this->translations = new \Doctrine\Common\Collections\ArrayCollection();
        }
    }
    
    /** @Entity */
    class NavigationElementTranslation
    {
        // ...
        /**
         * @ManyToOne(targetEntity="NavigationElement", inversedBy="translations")
         * @JoinColumn(name="navigation_element_id", referencedColumnName="id")
         */
        private $navigationElement;
        // ...
    }
    

    您可以将 getLabel($languageId) 方法添加到 NavigationElement 实体中,该实体搜索翻译以获取正确的标签:

    public function getLabel($languageId) {
    
        foreach($this->translations as $trans) {
            if($trans->languageId == $languageId)
                return $trans->label;
        }
    
        throw new InvalidArgumentException();
    }
    

    您可以使用以下 DQL 确保仅将所需的翻译加载到 $translations 属性中:

    $query = $em->createQuery(
        "SELECT ne, net
         FROM Entity\NavigationElement ne
         JOIN ne.translations net WITH net.languageId = :langId"
    );
    $query->setParameter('langId', $languageId);
    $navigationElements = $query->execute();
    

    这种情况听起来像是您想要积极缓存的情况。确保你也研究了Doctrine 2's caching 机制。

    此外,如果您发现用于翻译的连接表开始变得难以管理,则可以在 PHP 中使用 gettext 很好地处理国际化。

    【讨论】:

    • 对于这个非常棒的解释,我非常感谢。我想我在理解创建一个实体(翻译)的必要性时遇到了问题,该实体(翻译)在我的领域内(本身)没有意义 - 但当然,鉴于您提供的示例,我不会直接访问它,但是元素本身却是透明的。
    • rojoca 的回答还算不错,不过他的最后一句话也是一个很大的暗示。您的直觉是正确的:国际化 (I18N) 很棘手,通常最好将这些东西从您的领域中抽象出来。 gettext 非常有用,还有其他机制。例如,来自 ZF 的 Zend_Locale 和 Zend_Translate 可以在框架之外有用地使用。如果这是一个大项目,你需要做很多翻译,(并且有时间),我会退后一步,开始对 i18n 做一些研究。
    • @timdev 感谢您的评论。该项目的范围只是(目前)模拟我们系统现在的运行方式。谢天谢地,它不是很复杂,所以我的解决方案也不需要(我不是试图添加尚不存在的功能)而且你是对的 - 我对 i18n 的理解非常有限,尽管在这种特定情况下我只需要处理(几个)域对象名称的简单翻译。我会看看你提到的 Packages 以及 symfony 的本地化和国际化功能。
    【解决方案2】:

    我还会指导任何必须解决相同问题的人查看以下教义扩展。

    http://www.gediminasm.org/article/translatable-behavior-extension-for-doctrine-2

    【讨论】:

    • 请注意任何偶然发现此问题的人:上述扩展使用 EAV 存储数据,因此对于小型数据集以外的任何内容都非常低效。如果您有大量需要翻译的实体并且您关心性能,那么您将不得不自己动手。
    • 你真的可以仅仅因为使用 EAV 就将某事归类为“效率极低”吗?我不是专家,但也许这可以解决一些性能问题gediminasm.org/article/…
    • @calumbrodie 该链接已离线(404);检查于 2016-06-08
    猜你喜欢
    • 1970-01-01
    • 2022-01-23
    • 2019-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多