【问题标题】:Can't send a list of items to backend to be removed from a list无法将项目列表发送到后端以从列表中删除
【发布时间】:2013-10-30 18:00:03
【问题描述】:

用户将从列表中选择一些要删除的项目。

我有两个选择,要么传递所选项目的 ID,要么传递它们在内存中的对象地址。

第一个问题是,发送所选项目的对象而不是其 id 是否正确?

  <input type="checkbox" name="selectedItems" value="${item}"/> 

   rather than

  <input type="checkbox" name="selectedItems" value="${item.id}"/> 

如果我应该发送项目的 ID,当我传递他们的 ID 时,创建一个对象并设置我无法从列表中删除它们的 ID,最好的方法是什么?

        Item item = new Item();
        item.setID(selectedItems.get(0));

        Basket basket = (Basket) session.get(Basket.class, Long.parseLong(basket_id));
        basket.getItems.remove(item); <<I cant remove them by just setting their ids!!

        session.update(basket);

【问题讨论】:

    标签: java hibernate jakarta-ee hibernate-mapping


    【解决方案1】:

    list.remove 方法从列表中删除第一次出现的指定元素。下面的代码块是从ArrayList源代码复制而来的:

    for (int index = 0; index < size; index++)
                    if (o.equals(elementData[index])) {
                        // REMOVE ITEM FROM THE LIST
                    }
    }
    

    它使用Object.equals 方法来检查要从列表中删除的对象的相等性。所以你需要重写Item 类中的equals 方法来判断哪些items 是相等的。而当你覆盖equals()时,你总是需要同时覆盖hashCode(),所以这两种方法是一致的

    现在,当传递Item 的实例以从list 中删除时,您需要设置用于实现equals 方法的Item 的所有属性的值。

    但您不应该使用database identifier (id) 来实现equals()。在保存实体之前,Hibernate 不会分配标识符值。因此,如果对象在保存之前被添加到Set,它的哈希码会在Set 包含时更改(在保存操作时),这与java.util.Set 的约定相反。您可以使用属性组合,这对于Item 的每个实例都是唯一的。

    【讨论】:

    • 谢谢,实体已经保存在数据库中,我需要删除用户选择的那些。这是否意味着如果选择了 10 个不同的项目,我必须检索所有项目的字段,然后对所有项目执行相同的方法?
    • 您不必从数据库中检索它们。您需要使用用户提交的数据创建 10 个项目,设置 equals 所需的属性并将它们传递给 basket.getItems.remove(item); 以从 list 中删除。现在您可以使用session.update(basket); 更新basket
    • 通过从 db 中检索它们,我的意思是篮子中的所有项目 session.get(Basket.class,12),我应该传递对象还是只传递 id ? id 可用于比较,因为它与我在 db 中的相同,所以我为什么要接收所有数据?这是否意味着我应该使用该对象? (第一种方法?)_
    • 要从数据库中检索basket,您可以使用idsession.get(Basket.class,12) 将加载带有items 列表的basket。现在要从item 列表中删除特定项目,使用Itemequals 方法中使用的属性创建Item,将它们传递给basket.getItems.remove(item) 并使用session.update(basket) 更新数据库。
    【解决方案2】:

    在删除之前加载项目对象。

    Item item = session.load(Item.class, selectedItems.get(0))
    

    然后调用

    basket.getItems.remove(item);
    

    【讨论】:

      【解决方案3】:

      在要删除对象的类中,您需要override equals() method。将其编码为if all member variables are equal, then the objects are equal。 Netbeans IDE 中提供了模板实现,它使用了更多检查,例如检查实例。

      Otherwise object member variables could all be same but still objects 
      will not be equal since they refer to different locations in memory heap.
      

      我的model classes几乎总是override equals() and toString() methods

      【讨论】:

        【解决方案4】:

        简单明了

        不要删除副本,在里面搜索:

        for(Iterator<Item> iterator = basket.getItems().iterator(); iterator.hasNext();)
        {
            Item currentItem = iterator.next();
        
            if(selectedItems.contains(currentItem.getId()))
            {
                iterator.remove();
            }
        }
        

        但是,如果您尚未覆盖 item.toString(),则切勿使用 value="${item}"

        【讨论】:

          【解决方案5】:

          您不能将您的 ArrayList 更改为 HashMap 并根据其 ID 存储对象吗?然后你可以用一行代码删除它们。

          【讨论】:

            【解决方案6】:

            总部。

            session.createQuery("delete from Item i where i.id in (:iids)").setParameter("iids", item_ids).executeUpdate();
            

            【讨论】:

              【解决方案7】:

              有几种方法,如果您对 hql 或 sql 感到满意,我更喜欢使用查询,

              1. 接近一个

                从 id in (x,y,z,xy...) 的表中删除;

              优点:您无需从数据库加载任何内容。您只需运行一个 sql 并获得响应。

              1. 接近二

              渴望将对象获取到内存中(Ofcoz,从客户端发送 ID)遍历项目列表并匹配 ID 并将其删除。刷新会话。

              【讨论】:

                【解决方案8】:

                不要直接渲染对象。不要这样做。那就是痛苦和疯狂。假设你这样做了,并且没有覆盖toString()

                <input type="checkbox" name="selectedItems" value="${item}"/>
                

                然后发生以下情况:

                • 您将项目提取到List,使用toString() 的默认class.name@address 实现来呈现每个项目。
                • 用户选择一些要删除的项目并提交表单,这会发出一个新的 HTTP 请求。原来的 List 项目已经消失了,所以这些地址指向……嗯,你不知道它们指向什么。

                (还有其他问题:如果恶意攻击者检查页面源,他们现在知道您正在运行基于 Java 的服务器。没有理由自愿提供这些信息。)

                现在,您可能会想“嘿,我将这些项目放在我的会话中”。现在您遇到了同样的问题:大多数会话处理实现将在将项目存储在会话中时将它们序列化,并在检索时将它们反序列化到新副本。您的对象引用现在毫无意义。

                您可以覆盖toString(),但为什么呢?只需在删除查询中传递 ID 并将它们发送到您的数据库。这样一来,如果有人决定更改 toString() 实现,就不会感到意外。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2022-12-20
                  • 1970-01-01
                  • 2018-10-04
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-06-10
                  相关资源
                  最近更新 更多