<tfoot id='EHd7o'></tfoot><legend id='EHd7o'><style id='EHd7o'><dir id='EHd7o'><q id='EHd7o'></q></dir></style></legend>
    <bdo id='EHd7o'></bdo><ul id='EHd7o'></ul>

  1. <i id='EHd7o'><tr id='EHd7o'><dt id='EHd7o'><q id='EHd7o'><span id='EHd7o'><b id='EHd7o'><form id='EHd7o'><ins id='EHd7o'></ins><ul id='EHd7o'></ul><sub id='EHd7o'></sub></form><legend id='EHd7o'></legend><bdo id='EHd7o'><pre id='EHd7o'><center id='EHd7o'></center></pre></bdo></b><th id='EHd7o'></th></span></q></dt></tr></i><div id='EHd7o'><tfoot id='EHd7o'></tfoot><dl id='EHd7o'><fieldset id='EHd7o'></fieldset></dl></div>
  2. <small id='EHd7o'></small><noframes id='EHd7o'>

    1. 如何在与 Doctrine 的多对多关系中避免重复条目?

      How to avoid duplicate entries in a many-to-many relationship with Doctrine?(如何在与 Doctrine 的多对多关系中避免重复条目?)

      • <legend id='0atkr'><style id='0atkr'><dir id='0atkr'><q id='0atkr'></q></dir></style></legend>

              <small id='0atkr'></small><noframes id='0atkr'>

                <bdo id='0atkr'></bdo><ul id='0atkr'></ul>
                  <tbody id='0atkr'></tbody>
                <tfoot id='0atkr'></tfoot>

                <i id='0atkr'><tr id='0atkr'><dt id='0atkr'><q id='0atkr'><span id='0atkr'><b id='0atkr'><form id='0atkr'><ins id='0atkr'></ins><ul id='0atkr'></ul><sub id='0atkr'></sub></form><legend id='0atkr'></legend><bdo id='0atkr'><pre id='0atkr'><center id='0atkr'></center></pre></bdo></b><th id='0atkr'></th></span></q></dt></tr></i><div id='0atkr'><tfoot id='0atkr'></tfoot><dl id='0atkr'><fieldset id='0atkr'></fieldset></dl></div>
                本文介绍了如何在与 Doctrine 的多对多关系中避免重复条目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                问题描述

                我正在使用 嵌入 Symfony 表单来添加和删除Tag 实体直接来自文章编辑器.文章 是拥有方 关联:

                I'm using an embed Symfony form to add and remove Tag entities right from the article editor. Article is the owning side on the association:

                class Article
                {
                    /**
                     * @ManyToMany(targetEntity="Tags", inversedBy="articles", cascade={"persist"})
                     */
                    private $tags;
                
                    public function addTag(Tag $tags)
                    {
                        if (!$this->tags->contains($tags)) // It is always true.
                            $this->tags[] = $tags;
                    }
                }
                

                条件在这里没有帮助,因为它始终为真,如果不是,则根本不会将新标签持久化到数据库中.这是 Tag 实体:

                The condition doesn't help here, as it is always true, and if it wasn't, no new tags would be persisted to the database at all. Here is the Tag entity:

                class Tag
                {
                    /**
                     * @Column(unique=true)
                     */
                    private $name
                
                    /**
                     * @ManyToMany(targetEntity="Articles", mappedBy="tags")
                     */
                    private $articles;
                
                    public function addArticle(Article $articles)
                    {
                        $this->articles[] = $articles;
                    }
                }
                

                我已将 $name 设置为唯一的,因为我想每次在表单中输入相同的名称时都使用相同的标签.但它不能这样工作,我得到了例外:

                I've set $name to unique, because I want to use the same tag every time I enter the same name in the form. But it doesn't work this way, and I get the exception:

                违反完整性约束:1062 重复条目

                Integrity constraint violation: 1062 Duplicate entry

                我需要更改什么才能使用 article_tag,这是提交标签名称时的默认连接表,它已经在 Tag 表中?

                What do I need to change to use article_tag, the default join table when submitting a tag name, that's already in the Tag table?

                推荐答案

                我几个月来一直在与类似的问题作斗争,终于找到了一个似乎在我的应用程序中运行良好的解决方案.这是一个复杂的应用程序,有很多多对多关联,我需要以最高效率处理它们.

                I have been battling with a similar issue for months and finally found a solution that seems to be working very well in my application. It's a complex application with quite a few many-to-many associations and I need to handle them with maximum efficiency.

                解决方案部分解释如下:http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/faq.html#why-do-i-get-exceptions-about-unique-constraint-failures-during-em-flush

                The solution is explained in part here: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/faq.html#why-do-i-get-exceptions-about-unique-constraint-failures-during-em-flush

                您的代码已经完成了一半:

                You were already halfway there with your code:

                public function addTag(Tag $tags)
                {
                    if (!$this->tags->contains($tags)) // It is always true.
                        $this->tags[] = $tags;
                }
                

                基本上我添加的内容是在关系的拥有方设置 indexedBy="name"fetch="EXTRA_LAZY",这在您的案例是文章实体(您可能需要水平滚动代码块才能看到添加内容):

                Basically what I have added to this is to set indexedBy="name" and fetch="EXTRA_LAZY" on the owning side of the relationship, which in your case is Article entity (you may need to scroll the code block horizontally to see the addition):

                class Article
                {
                    /**
                     * @ManyToMany(targetEntity="Tags", inversedBy="articles", cascade={"persist"}, indexedBy="name" fetch="EXTRA_LAZY")
                     */
                    private $tags;
                

                您可以阅读在这里了解 fetch="EXTRA_LAZY" 选项.

                你可以在此处阅读 indexBy="name" 选项.

                接下来,我将您的 addTag() 方法的版本修改如下:

                Next, I modified my versions of your addTag() method as follows:

                public function addTag(Tag $tags)
                {
                    // Check for an existing entity in the DB based on the given
                    // entity's PRIMARY KEY property value
                    if ($this->tags->contains($tags)) {
                        return $this; // or just return;
                    }
                    
                    // This prevents adding duplicates of new tags that aren't in the
                    // DB already.
                    $tagKey = $tag->getName() ?? $tag->getHash();
                    $this->tags[$tagKey] = $tags;
                }
                

                注意:??空合并运算符需要 PHP7+.

                NOTE: The ?? null coalesce operator requires PHP7+.

                通过将标签的获取策略设置为EXTRA_LAZY,以下语句会导致 Doctrine 执行 SQL 查询以检查数据库中是否存在具有相同名称的标签(有关更多信息,请参阅上面的相关 EXTRA_LAZY 链接):

                By setting the fetch strategy for tags to EXTRA_LAZY the following statement causes Doctrine to perform a SQL query to check if a Tag with the same name exists in the DB (see the related EXTRA_LAZY link above for more):

                $this->tags->contains($tags)
                

                注意: 只有在设置了传递给它的实体的PRIMARY KEY 字段时,它才能返回true.当使用像 ArrayCollection::contains() 这样的方法时,Doctrine 只能根据该实体的 PRIMARY KEY 查询数据库/实体映射中的现有实体.如果 Tag 实体的 name 属性只是一个 UNIQUE KEY,这可能就是它总是返回 false 的原因.您需要一个PRIMARY KEY才能有效地使用contains()等方法.

                NOTE: This can only return true if the PRIMARY KEY field of the entity passed to it is set. Doctrine can only query for existing entities in the database/entity map based on the PRIMARY KEY of that entity, when using methods like ArrayCollection::contains(). If the name property of the Tag entity is only a UNIQUE KEY, that's probably why it's always returning false. You will need a PRIMARY KEY to use methods like contains() effectively.

                addTag() 方法中 if 块之后的其余代码通过 PRIMARY KEY 属性中的值(首选,如果不为空)或通过 Tag 实体的散列(在 Google 中搜索PHP + spl_object_hash",Doctrine 用于索引实体).因此,您正在创建一个索引关联,以便如果您在刷新前两次添加相同的实体,它只会在相同的键处重新添加,但不会重复.

                The rest of the code in the addTag() method after the if block creates a key for the ArrayCollection of Tags either by the value in the PRIMARY KEY property (preferred if not null) or by the Tag entity's hash (search Google for "PHP + spl_object_hash", used by Doctrine to index entities). So, you are creating an indexed association, so that if you add the same entity twice before a flush, it will just be re-added at the same key, but not duplicated.

                这篇关于如何在与 Doctrine 的多对多关系中避免重复条目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

                相关文档推荐

                Is PHP or PHP based web framework stateful or stateless?(PHP 或基于 PHP 的 Web 框架是有状态的还是无状态的?)
                How to parse django style template tags(如何解析 django 样式模板标签)
                What is a good setup for editing PHP in Emacs?(在 Emacs 中编辑 PHP 的好设置是什么?)
                How to check whether specified PID is currently running without invoking ps from PHP?(如何在不从 PHP 调用 ps 的情况下检查指定的 PID 当前是否正在运行?)
                What#39;s the difference between escapeshellarg and escapeshellcmd?(escapeshellarg 和escapeshellcmd 有什么区别?)
                php in background exec() function(php 后台 exec() 函数)

              • <i id='rT670'><tr id='rT670'><dt id='rT670'><q id='rT670'><span id='rT670'><b id='rT670'><form id='rT670'><ins id='rT670'></ins><ul id='rT670'></ul><sub id='rT670'></sub></form><legend id='rT670'></legend><bdo id='rT670'><pre id='rT670'><center id='rT670'></center></pre></bdo></b><th id='rT670'></th></span></q></dt></tr></i><div id='rT670'><tfoot id='rT670'></tfoot><dl id='rT670'><fieldset id='rT670'></fieldset></dl></div>
                  <bdo id='rT670'></bdo><ul id='rT670'></ul>

                  <legend id='rT670'><style id='rT670'><dir id='rT670'><q id='rT670'></q></dir></style></legend>

                      <small id='rT670'></small><noframes id='rT670'>

                      <tfoot id='rT670'></tfoot>

                          <tbody id='rT670'></tbody>