Why does ".contains" return false for objects pulled directly from the collection?
private Collection<Episode> episodes = new ArrayList<Episode>(); public void checkEpisodes(String string) { for(Episode episode : this.episodes){ System.out.println(string + this.episodes.contains(episode)); } }
Why does the above code print false?
I use the collection because this is what ormlite allows. I think the problem can be caused by ormlite anyway, because a very similar class has an identical method that outputs true.
What I'm trying to do is change the object returned:
public Episode findEpisode(int num) { checkEpisodes("Find: "); for(Episode episode : this.episodes) { if(episode.getNumber()==num) { return episode; } } return null; }
But the modification of this object is not saved. I guess it is not in the collection.
My solution that works, but not perfect:
public void modifyEpisode(Episode episode) { checkEpisodes("Modify: "); for (Iterator<?> it = this.episodes.iterator(); it.hasNext();) { if (((Episode) it.next()).getNumber()==episode.getNumber()) { it.remove(); addEpisode(episode.getNumber(), episode.getLink(), episode.getLinkLabel()); } } }
If you need to see more of my code, just ask, the project is somewhat involved, but it is posted on sourceforge, and I can post a link to it if necessary.
for(Episode episode : this.episodes) { System.out.println(string + this.episodes.contains(episode)); }
Why does the above code print false?
In a general sense, using the standard collection is the only way to see if there are errors in your equals()
method. In most collections, contains()
iterates through the collection and uses equals()
. Object.equals()
will work, so it may be that you have redefined the default equals
method, and there is an error in it.
It also means ORMLite . If the collection is impatient, it calls contains()
on the internal ArrayList
for the element that will use equals()
. If the collection is lazy, then it uses an iterator over the table and, again, uses equals()
to view matches.
Edit:
Yeah. You claim that you did not redefine the equals()
method.
One important thing to keep in mind (from the point of view of ORMLite) is that it is a lazy collection, there is no object storage in memory. When you iterate over a lazy collection, you get an instance of your Episode
object from the database. Then, when you call contains()
, it repeats again through the collection, creating new Episode
objects from the database. It tries to compare two objects, but they will never be equal if you use Object.equals()
, because the same object reference does not exist.
You must override the equals()
method to get contains()
to work with lazy collections.
Also, although your post probably simplifies your code, you might consider pulling a lazy collection into an array, and then repeating this. You cannot do contains()
in an array, but if you need to search for an array, you will not repeat twice through the database.
Edit:
Thus, the solution turned out to be more complicated. It turns out that the OP had a Show
object, with an impatient collection of Season
objects, each of which had another collection of Episode
objects. By default, when ORMLite has nested impatient collections, the inner shell turns into a lazy collection for performance reasons. Unfortunately, this is poorly documented in version 4.40. You can change this by setting maxEagerLevel = 2
(or more) in the Show
collection of objects. See the documentation for maxEagerLevel
.
@ForeignCollectionField(eager = false, maxEagerLevel = 2) ForeignCollection<Season> seasons;
Now, ormlite, an object relational mapper, manages the object and its state of change. It also provides a means to save the changed episode; one of your mentioned items. But regarding the error: you have to create equals based on value. In ORM and similar managed libraries, serialization can provide you with different instances / proxies for the same object, and access to methods can be intercepted by processing the byte code (AOP).
Modification example:
for (Order order : account.orders()) { // if we are changing some field in the order order.setAmount(123); // then we need to update it in the database account.orders.update(order); }