首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么ebean (ORM)模型-对象上的iterator.remove()不能工作?

为什么ebean (ORM)模型-对象上的iterator.remove()不能工作?
EN

Stack Overflow用户
提问于 2015-01-25 12:41:40
回答 1查看 267关注 0票数 0

在我的Play 2.3应用程序中,我使用ebean作为ORM。当我迭代我的HashSet以删除匹配的模型对象时,iterator.remove()无法工作。为了确定要删除哪个模型,我甚至不依赖于modelObject.equals()-method,而只是比较一个字符串:

代码语言:javascript
复制
public boolean deleteToken(final User user, final String token) {
    if (token == null || token.isEmpty()) return false;

    int previousTokenSetSize = user.tokens.size();
    Iterator<Token> iterator = user.tokens.iterator();
    while (iterator.hasNext()) {
      final Token tokenObj = iterator.next();
      if (tokenObj.token.equalsIgnoreCase(token)) { // simple String-comparison
        iterator.remove(); // this line is reached, but no effect!
        userRepository.delete(tokenObj);
        break;
      }
    }

    if (user.tokens.size() != previousTokenSetSize) {
      userRepository.update(user);
      return true;
    }
    return false;
  }

请注意:如果我在没有数据库的情况下进行单元测试,这个方法确实可以工作。如果我在运行假应用程序中对“实时”模型和测试数据库做同样的操作,它就不起作用了。在调试时,我看到迭代后没有删除任何内容(当我将模型删除从迭代中移出或放在iterator.remove()之前时,没有什么不同)。我真的不明白这一点,因为我没有传递另一个对象,只是一个字符串,并且只是试图删除迭代器的当前对象。在迭代时,我也不会在remove()之前修改集合,因此哈希代码不应该改变(或者我是不是遗漏了什么?)

我确实为我的模型实现了equals()hashCode() (见下文),甚至简化了这些,排除了超级,但它没有改变任何东西。我的想法不多了,我希望能得到任何帮助。

Token-model类:

代码语言:javascript
复制
@Entity
public class Token extends Model {

    @Id
    public Long id;

    @ManyToOne()
    @JsonIgnore
    @Required
    @Column(nullable = false)
    public User user;

    @Column(length = 255, unique = true, nullable = false)
    @MaxLength(255)
    @Required
    public String token;

    public Token(User user, String token) {
        this.user = user;
        this.token = token;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Token token = (Token) o;

        if (id != null ? !id.equals(token.id) : token.id != null) return false;
        if (user.id != null ? !user.id.equals(token.user.id) : token.user.id != null) return false;
        if (!token.equals(token.token)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + (id != null ? id.hashCode() : 0);
        result = 31 * result + (user.id != null ? user.id.hashCode() : 0);
        result = 31 * result + token.hashCode();

        return result;
    }
}

User供参考(简化):

代码语言:javascript
复制
@Entity
public class User extends Model {

    @Id
    public Long id;

    // simplified to stress the relevant parts

    @OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
    @JsonIgnore
    public final Set<Token> tokens = new HashSet<>();

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        // simplified, irrelevant variables excluded
        if (tokens != null ? !tokens.equals(user.tokens) : user.tkens != null) return false;
        if (id != null ? !id.equals(user.id) : user.id != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        // simplified, irrelevant variables excluded
        int result = 17;
        result = 31 * result + (id != null ? id.hashCode() : 0);
        result = 31 * result + (tokens != null ? tokens.hashCode() : 0);
        return result;
    }
}

编辑

我确实找到了这个:HashSet.remove() and Iterator.remove() not working

所以,我猜对象被添加到HashSet之后就会改变。因为使用ebean,我创建了Token-object,将它添加到用户的令牌集中,然后在DB中更新用户:

代码语言:javascript
复制
public String createToken(final User user) {
    final String newToken = generateToken();
    final Token token = new Token(user, newToken);
    user.tokens.add(token);

    userRepository.update(user);

    return newToken;
}

这意味着在添加时,Token-object的ID是null,然后ebean负责处理ID。如果这使令牌对象不可移动,我应该如何处理这个问题?我试着将id从Tokenequals()hashCode()方法中排除,但这并没有改变任何事情。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-01-25 14:41:53

好的,我掉进了基于哈希集合的可变字段的陷阱中。它缩小了我在编辑中的范围:当使用像ebean这样的ORM时,id-field是可变的(以及其他字段,比如用@CreatedTimestamp注释的日期)。所以我们学到了什么:

在hashCode()中使用可变字段会导致灾难。当这个类的实例放在基于哈希的集合中,比如HashSet或HashMap (作为映射键)时,灾难就会发生。

来源:http://blog.mgm-tp.com/2012/03/hashset-java-puzzler/

这意味着我必须在保存后从数据库中重新加载这些模型对象,因为只有这样,id-field才会在它们被添加到HashSet时被填充,并且只有这样它们才能被删除。另一种方法是将id-fields排除在hashCode()-method之外,但是由于它们是唯一的标识符,所以我会小心处理(我想如果您确保包含了其他唯一的字段,那就好了)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28136510

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档