This Bugzilla instance is deprecated, and most Eclipse projects now use GitHub or Eclipse GitLab. Please see the deprecation plan for details.
Bug 256978 - Support of duplicate items in lists
Summary: Support of duplicate items in lists
Status: NEW
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Eclipselink (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows Vista
: P5 enhancement with 3 votes (vote)
Target Milestone: ---   Edit
Assignee: Nobody - feel free to take it CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 395438 (view as bug list)
Depends on: 249037
Blocks:
  Show dependency tree
 
Reported: 2008-11-29 16:48 EST by Gili Mising name CLA
Modified: 2022-06-09 10:26 EDT (History)
7 users (show)

See Also:


Attachments
EclipseLink log (114.25 KB, application/octet-stream)
2008-11-30 01:51 EST, Gili Mising name CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Gili Mising name CLA 2008-11-29 16:48:55 EST
Build ID: N/A

Steps To Reproduce:
Given the following method:
@ManyToMany
@JoinTable(name = "playlist_to_clip",
joinColumns = @JoinColumn(name = "playlist_id", nullable = false),
inverseJoinColumns = @JoinColumn(name = "clip_id", nullable = false))
public List<Clip> getClips();

EclipseLink will generate a join-table with 2 columns (playlist_id, clip_id) with a primary key defined over those two. This makes it impossible to store duplicate clips per playlist which is clearly implied by the use of List instead of Set.

EclipseLink should allow duplicates if the method returns any collection except a Set. Specifically, Collection and List should definitely allow duplicates.

More information:
Comment 1 Gili Mising name CLA 2008-11-29 18:40:45 EST
It looks like the only thing DDL is doing wrong is generating a primary key. Omitting it fixes the problem for me.
Comment 2 Gili Mising name CLA 2008-11-29 22:10:42 EST
Changed severity to critical because even once I remove the primary key by hand I run into the following bug:

1) A playlist has a unique "name" and a list of clips
2) Save a new playlist with 3 clips to the database
3) Look up that same playlist by name
4) The database clearly contains 3 clips associated with the playlist, but EclipseLink returns *one* clip from the 2nd-level cache
5) Repeating this query keeps on returning one clip
6) Restart EclipseLink (thereby flushing the 2nd-level cache)
7) Reissue the query in #4
8) 3 clips are returned (correct value)

I believe I'm stuck at this point. I don't think I can implement my application until this bug is fixed.
Comment 3 Gili Mising name CLA 2008-11-30 01:50:47 EST
I'm going to attach the EclipseLink log with logging level "finest". Here are specific lines to look at...

Line 611: Notice how we insert PlaylistVersion[id=1301, version=39] with *two* video elements.

Line 620 and 623: Notice how we insert [video_id=2, playlist_id=1301] *twice* into the "playlist_to_video" table. This reinforces the fact that there are *two* videos associated with PlaylistVersion #1301.

Line 642: Notice how PlaylistVersion[id=1301, version=39] suddenly contains *one* video element.
Comment 4 Gili Mising name CLA 2008-11-30 01:51:33 EST
Created attachment 119084 [details]
EclipseLink log
Comment 5 Gili Mising name CLA 2008-12-01 13:17:27 EST
See http://www.nabble.com/%40ManyToMany-relationship-for-a-List--td20749567.html for a related discussion.
Comment 6 Tom Ware CLA 2008-12-03 13:10:52 EST
Discussion of workaround from Nabble article above:

  One workaround I can think of is to add another level of indirection. 

i.e. 

PlayList has a OneToMany to PlayListItem 
PlayListItem has a OneToOne to Video 
PlayListItem has its own identity. 

You could even implement the mthods in PlayList to make PlayListItem pretty much 
transparent to whoever was using your model. 


----


I don't understand how "PlayListItem has a OneToOne to Video" would work. Each video can be associated with multiple playlists. As a consequence, each PlaylistItem would need to be associated with multiple videos as well. Shouldn't I do this instead? 

Playlist has a OneToMany to PlaylistItem 
PlaylistItem has a OneToMany to Video 
PlaylistItem has its own identity 

This would give you: 

Playlist[id] 
Video[id] 
PlaylistItem[id, playlist_id, video_id] 

What do you think? 

----


  Depending on how you want things to work, it is certainly possible to do it 
the way you have suggested.  Let me explain a bit further my suggestion, and 
then you can decide which fits your model better. 

- PlayList has a OneToMany to PlayListItem 
- PlayListItem has a OneToOne to Video 
- PlayListItem has its own identity. 

Consider the following objects: 
- PlayList: PL1 
- Video: V1 
- Video: V2 

Lets say we want to add V1 to PL1: 

1. pl1.add(v1) 
- on this call, we create an instance of PlayListItem pli1 and associate it with 
v1: 
- pli1 = new PlayListItem() 
- pli1.video = v1 
- we then associate pli1 to pl1. 
- pl1.addPlayListItem(pli1) 

2. p11.add(v2) 
- we do basically the same thing as above: 
- pli2 = new PlayListItem() 
- pli2.video = v2 
- pl1.addPlayListItem(pli2) 

3. pl1.add(v1) 
- add a duplicate item 
- pli3 = new PlayListItem() // this will have a different PK than pli1 
- pli3.video = v1 
- pl1.addPlayListItem(pli3) 
- The key here is keys that form the list are the foreign keys on PlayList and 
PlayListItem, so you do not get conflicts where there are duplicate items. 
PlayListItem has separate foreign keys that associate it with Video. 

When we are done: 

pl1 has a list of 3 PlayListItems (pli1, pli2, pli3) 
pli1 has a 1-1 relationship with v1 
pli2 has a 1-1 relationship with v2 
pli3 has a 1-1 relationship with v1 

With this set of mappings, pl1 hold 2 pointers to v1 


----
I think I see it now. I guess I was confused by: 

class PlaylistItem 
{ 
  @OneToOne 
  public Video getVideo(); 
} 

I thought @OneToOne meant that there may only be one PlaylistItem for every Video but (correct me if I'm wrong) what @OneToOne actually means is that there that every PlaylistItem has exactly one Video associated with it. **The relationship says nothing about the association from the remote end** Is that correct? 

PS: What's the difference on a table-level between @ManyToOne and @OneToOne? Don't they both result in the same schema in this case? 

I mentioned @ManyToOne would result in: 

Playlist[id] 
Video[id] 
PlaylistItem[id, playlist_id, video_id] 

Wouldn't @OneToOne result in the same? 
----

   You are correct, the OneToOne relationship from PlayListItem to Video does 
not restrict how many PlayListItems can refer to the same Video. 

   ManyToOne is used in JPA to be explicit about the fact that a relationship is 
on the Many-side of a OneToMany relationship.  In EclipseLink, both OneToOne and 
ManyToOne are implemented with the same class and therefore can be used to end 
up with the same schema. 

----


'm going to try your approach but I don't think you can hide the details under the hood. If I want to add a new Playlist->Video relationship I'm going to need to either expose PlaylistItem to the end-user (to populate and save) or expose a save(Playlist, Video) method in the service layer. Either approach is ugly. Originally I simply used Playlist.getVideos().add() or remove() and the changes got persisted under the hood. I wish I could have a similarly clean approach (without breaking my layers). 

----
Nevermind, I got it working. I now expose "List<Video> VideoManager.getVideos(Playlist)" and the list implementation handles PlaylistItem under the hood.

Comment 7 Doug Clarke CLA 2008-12-16 07:44:52 EST
I agree that replacing the M:M with a 1:M->1:1 is the way to go to allow multiple relationships to the same object in the same collection. This also has the effect of uniquely identifying each relationship in the join table as well. Without this it would not be possible to remove one of the items from the list without removing all of them.

I am unsure what we do in EclipseLink to handle this. Maybe a how-to illustrating the pattern is the best solution.
Comment 8 Gili Mising name CLA 2008-12-16 09:35:59 EST
Doug,

Why not handle this seamlessly under the hood in EclipseLink? For example, users could specify a @ManyToMany with @JoinTable and EclipseLink would implement it as a M:1 - 1:1 under the hood.
Comment 9 Gili Mising name CLA 2008-12-26 14:54:41 EST
What does the JPA standard say about this? My own interpretation is that the standard goes out of its way to talk about persisting Lists (versus Sets). Clearly they expect implementations to be able to persist Lists. I fail to see how one can say you support persisting Lists *without* supporting duplicates, since duplicates are one of the main reasons for using Lists in the first place.

In short: persisting Lists, whether they contain duplicates or not, should "just work".
Comment 10 Doug Clarke CLA 2009-01-06 08:50:20 EST
In order to persist duplicates in a list there must be a unique way to identify each entry. 

In the case of ManyToMany the join table is typically a combination of the two primary key sets of source and target. To support duplicates an additional column would be required in the join and the state of this maintained. the only way to do this transparently would be to use the index in the list as the additional value to uniquely identify each entry and support full CRUD operations on each relation.

We should ensure this case is supported when we add JPA 2.0's support for maintaining ordering.

http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/ordered_lists

Comment 11 Tom Ware CLA 2009-04-16 11:03:43 EDT
Updating priority due to revised bug categorization process.  See the following page for details:

http://wiki.eclipse.org/EclipseLink/Development/Bugs/Guidelines#Priority_and_Target_Milestone 

If you feel the updated priority is incorrect, please send an email to eclipselink-users@eclipse.org.
Comment 12 Tom Ware CLA 2012-11-30 07:48:53 EST
*** Bug 395438 has been marked as a duplicate of this bug. ***
Comment 13 Johannes Neubauer CLA 2016-02-25 10:17:08 EST
This bug is still a big issue. Is there no generic solution to this? Lists with duplicate entries are "possible" regarding JPA, isn't it?
Comment 14 Marc Dzaebel CLA 2017-03-12 13:15:09 EDT
Johannes, the Wiki says (https://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/ordered_lists) that already JPA 2.0 "should enable the storage of duplicates in ManyToMany lists" and comment authors like Doug too. In fact, EclipseLink still does not persist lists with duplicate entities, which is catastrophic is my case. However, some people say, that JPA does not really require duplicates to be persisted. So this is clearly an issue that should have been clarified in JPA 2.1 (but isn't) or 2.2. There should also be a test case in the TCK. I agree with you, there should be a documented workaround but currently, it seems, they think that this problem has P5 (lowest priority). Would be interesting to know, whether other providers support duplicates, but changing the persistence provider for an application server isn't always easy/possible. This is an extremly time consuming problem. At the end, we'll have to manage our relation manually, as we did not achieve anything for 8 years. I would absolutely appreciate just to understand why the priority is so low.
Comment 15 Johannes Neubauer CLA 2017-03-12 14:42:18 EDT
@Marc: The question was rhetorical, but I agree with you this is a major issue and not a low priority one.

To answer your question: Yes, Hibernate is able to store duplicate entries to a list.
Comment 16 Eclipse Webmaster CLA 2022-06-09 10:26:47 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink