<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 的多对多关系中避免重复条目?

      时间:2023-08-19

      • <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 的多对多关系中避免重复条目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                上一篇:学说不允许 ResultSetMappingBuilder 工作 下一篇:Doctrine 2 中的行数

                相关文章

              • <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>