ManyToMany relationship do not work properly
fla83tn Nov 20, 2007 11:55 AMHi to all,
I'm working on jboss 4.2.1GA and I'm stuck with a simple ManyToMany relationship..
I have this relation between Users and Sources (of rss feeds - URLs in practice). I followed all tutorial about how to do it and I tried a lot of solutions but I can't figure out why it doesn't work!
Here's the entity class User:
package nc.entities.user; import javax.persistence.*; import java.util.Collection; import java.util.ArrayList; import nc.entities.source.Source; @Entity(name="User") @Table(name="USERS") //Named queries expressed the Java Persistence query language @NamedQueries( { @NamedQuery( name="User.findByNickName", query="SELECT u FROM User u WHERE u.nick LIKE :nick" ), @NamedQuery( name="User.deleteAll", query="DELETE FROM User u" ), @NamedQuery( name="User.selectAll", query="SELECT u FROM User u" ) } ) public class User { private int userId; private String name; private String password; private String nick; private Collection<Source> sources; /** Entities must have a public no-arg constructor */ public User() { } @Id @TableGenerator(name="USER_ID_GENERATOR", table="ID_GEN", pkColumnName="GEN_KEY", valueColumnName="GEN_VALUE", pkColumnValue="USER_ID", allocationSize=1) @GeneratedValue(strategy=GenerationType.TABLE,generator="USER_ID_GENERATOR") public int getUserId() { return userId; } public String getName() { return name; } public String getPassword(){ return password; } public String getNick() { return nick; } public void setUserId(int id) { this.userId=id; } public void setName(String name) { this.name=name; } public void setPassword(String password){ this.password=password; } public void setNick(String nick) { this.nick=nick; } // N:M bidirectional - TO @ManyToMany(cascade={CascadeType.ALL},fetch=FetchType.LAZY,mappedBy="users",targetEntity=Source.class) public Collection<Source> getSources() { return sources;} public void setSources(Collection<Source> sources) { this.sources = sources;} }
and here's the code of entity Source
package nc.entities.source; import javax.persistence.*; import java.util.Collection; import java.util.ArrayList; import nc.entities.user.User; import nc.entities.feed.Feed; @Entity(name="Source") @Table(name="SOURCES") @NamedQueries( { @NamedQuery( name="Source.findByUrl", query="SELECT s FROM Source s WHERE s.url LIKE :url" ), @NamedQuery( name="Source.deleteAll", query="DELETE FROM Source s" ) } ) public class Source { private int sourceId; private String url; private Collection<User> users; private Collection<Feed> feeds; /** Entities must have a public no-arg constructor */ public Source(){ } public void setUrl(String url){this.url=url;} public void setSourceId(int id){this.sourceId=id;} @Id @TableGenerator(name="SOURCE_ID_GENERATOR", table="ID_GEN", pkColumnName="GEN_KEY", valueColumnName="GEN_VALUE", pkColumnValue="SOURCE_ID", allocationSize=5) @GeneratedValue(strategy=GenerationType.TABLE,generator="SOURCE_ID_GENERATOR") public int getSourceId(){return sourceId;} public String getUrl() {return url;} // N:M: bidirectional - FROM @ManyToMany(cascade={CascadeType.ALL}, fetch=FetchType.LAZY, targetEntity=User.class) //@JoinTable(name="SOURCE_USER") @JoinTable(name = "SOURCE_USER", joinColumns = @JoinColumn(name = "SOURCE_ID", referencedColumnName="sourceId"), inverseJoinColumns = @JoinColumn(name = "USER_ID", referencedColumnName="userId")) public Collection<User> getUsers() { return users; } public void setUsers(Collection<User> users) { this.users = users; } // 1:N unidirectional: FROM @OneToMany(cascade={CascadeType.ALL},fetch=FetchType.LAZY) public Collection<Feed> getFeeds() { return feeds; } public void setFeeds(Collection<Feed> feeds) { this.feeds = feeds; } }
The table is SOURCE_USER is created correctly, users and sources are also stored correctly! The function getUsers or getSources works fine if some data are inserted manually in the SOURCE_USER table, but if I perform a setUsers nothing is inserted in that table.
Here's the code of a session bean where I try to insert relationship data:
@Stateless @Remote(UserSessionFacade.class) @TransactionManagement(TransactionManagementType.CONTAINER) public class UserSessionFacadeBean implements UserSessionFacade { static Logger logger=Logger.getLogger(UserSessionFacadeBean.class); @Resource // Injection using annotations private SessionContext sessionContext; //@PersistenceContext(type=PersistenceContextType.EXTENDED,unitName="NewsCrawlerPu") @PersistenceContext//(unitName="NewsCrawlerPu") private EntityManager manager; @TransactionAttribute(TransactionAttributeType.REQUIRED) public void createSources(UserDTO userDTO) { if (userDTO == null) { logger.error("UserDTO passed is null!");return; } logger.debug("Adding sources to a user - dto passed is:".concat(userDTO.toString())); if(userDTO.getId()!=null || userDTO.getNick()!=null ){ User user=null; if(userDTO.getId()!=null) user = manager.find(User.class,userDTO.getId()); else user = findUserByNick(userDTO.getNick()); if(user==null){ logger.error("User not found in Db.."); //Abort if user does not exist sessionContext.setRollbackOnly(); } else{ logger.trace("User found in db"); SourceDTO[] s=userDTO.getSources(); Collection<User> list; Object o=null; int length; if(s!=null && (length=s.length)!=0){ for (int i = 0; i < length; i++) { logger.trace("for cicle: search for "+s.getUrl()); Source src = null; Query q=manager.createNamedQuery("Source.findByUrl"); logger.trace("Creating namedQuery..."); try{ o=q.setParameter("url",s.getUrl()).getSingleResult(); }catch(NoResultException e){ logger.warn("Source "+s.getUrl()+" not found!"); o=null; }catch(NonUniqueResultException e){ logger.error("No unique result found!"); o=null; }catch(Exception e){ logger.error("Wrong query: MUST be a SELECT!"); o=null; } if(o!=null){ src=(Source)o; logger.debug("Source already present in Db: "); logger.debug("checking if user already hold it"); Collection <User>coll = src.getUsers(); Iterator<User> iter = coll.iterator(); boolean found = false; while (iter.hasNext() && found==false) { User u = iter.next(); logger.trace("User: "+u.getUserId()+", "+u.getName()); if (u.getUserId()==user.getUserId()) found = true; } list = new ArrayList(coll); if (!found) { logger.debug("Register user to that Source"); list.add(user); src.setUsers(list); manager.merge(src); manager.refresh(src); } else { logger.debug("User already registered to that Url"); } }else{ logger.debug("New Source (not found in Db): adding user to it"); src=SourceAssembler.createSource(s); list = new ArrayList<User>(); list.add(user); src.setUsers(list); manager.persist(src); manager.refresh(src); } } }else{ logger.warn("No source to add...Strange!"); } } }else{ logger.error("Missing user id in the passed DTO or id not valid!"); } } ..... .....
Any suggest?