This week's giveaway is in the Android forum.
We're giving away four copies of Android Security Essentials Live Lessons and have Godfrey Nolan on-line!
See this thread for details.
The moose likes Object Relational Mapping and the fly likes Why does EJB assume a join table and how do i get around it? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Databases » Object Relational Mapping
Bookmark "Why does EJB assume a join table and how do i get around it?" Watch "Why does EJB assume a join table and how do i get around it?" New topic
Author

Why does EJB assume a join table and how do i get around it?

Matt S Andersson
Greenhorn

Joined: May 14, 2009
Posts: 4
I am just starting out with EJB:s and i ran into this problem. Can someone please help me out?

I have two tables: TOURNAMENT and EVENT. They have a one-to-many relation: a tournament can have zero, one or many events.

My tables are in an Oracle XE database:

CREATE TABLE TOURNAMENT
(
ID NUMBER NOT NULL,
NAME VARCHAR2(100 BYTE),
STATUS VARCHAR2(20 BYTE),
DESCRIPTION VARCHAR2(1000 BYTE),
START_DATE DATE,
END_DATE DATE,
START_BALANCE NUMBER(10,2),
MAX_PARTICIPANTS NUMBER,
UPDTS DATE
)

CREATE TABLE EVENT
(
ID NUMBER NOT NULL,
TOURNAMENT_ID NUMBER NOT NULL,
NAME VARCHAR2(100 BYTE),
START_DATE DATE,
END_DATE DATE,
STATUS VARCHAR2(20 BYTE),
UPDTS DATE
)

Now i created a session EJB for tournament:
package oracle;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import java.sql.Timestamp;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;

@Entity
@NamedQueries({
@NamedQuery(name = "Tournament.findAll", query = "select o from Tournament o"),
@NamedQuery(name = "Tournament.findByName", query = "select o from Tournament o where o.name = :P_name")
})

public class Tournament implements Serializable {
private String description;
@Column(name="END_DATE")
private Timestamp endDate;
@Id
@Column(nullable = false)
private Long id;
@Column(name="MAX_PARTICIPANTS")
private Long maxParticipants;
private String name;
@Column(name="START_BALANCE")
private Double startBalance;
@Column(name="START_DATE")
private Timestamp startDate;
private String status;
private Timestamp updts;

private List<Event> events = new ArrayList<Event>();
@OneToMany(cascade={CascadeType.ALL})
@JoinColumn(name="TOURNAMENT_ID")
public List<Event> getEvents() {
System.out.println("------------->inne i getEvents()");
return this.events;
}

public void setEvents(List<Event> inEvents) {
this.events = inEvents;
}

public Tournament() {
}

public Tournament(String description, Timestamp endDate, Long id,
Long maxParticipants, String name, Double startBalance,
Timestamp startDate, String status, Timestamp updts) {
this.description = description;
this.endDate = endDate;
this.id = id;
this.maxParticipants = maxParticipants;
this.name = name;
this.startBalance = startBalance;
this.startDate = startDate;
this.status = status;
this.updts = updts;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public Timestamp getEndDate() {
return endDate;
}

public void setEndDate(Timestamp endDate) {
this.endDate = endDate;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public Long getMaxParticipants() {
return maxParticipants;
}

public void setMaxParticipants(Long maxParticipants) {
this.maxParticipants = maxParticipants;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Double getStartBalance() {
return startBalance;
}

public void setStartBalance(Double startBalance) {
this.startBalance = startBalance;
}

public Timestamp getStartDate() {
return startDate;
}

public void setStartDate(Timestamp startDate) {
this.startDate = startDate;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public Timestamp getUpdts() {
return updts;
}

public void setUpdts(Timestamp updts) {
this.updts = updts;
}

//Workaround for serialization error
private void writeObject(ObjectOutputStream out) throws IOException {
this.events.size();
out.defaultWriteObject();
}

}

*and one for event:*

package oracle;

import java.io.Serializable;

import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@NamedQueries({
@NamedQuery(name = "Event.findAll", query = "select o from Event o")
})
@Table(name = "EVENT")
public class Event implements Serializable {
private Timestamp endDate;
private Long id;
private String name;
private Timestamp startDate;
private String status;
private Long tournamentId;
private Timestamp updts;

public Event() {
}

public Event(Timestamp endDate, Long id, String name, Timestamp startDate,
String status, Long tournamentId, Timestamp updts) {
this.endDate = endDate;
this.id = id;
this.name = name;
this.startDate = startDate;
this.status = status;
this.tournamentId = tournamentId;
this.updts = updts;
}

@Id
@Column(name="ID", nullable = false)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}

@Column(name="END_DATE")
public Timestamp getEndDate() {
return endDate;
}
public void setEndDate(Timestamp endDate) {
this.endDate = endDate;
}

@Column(name="NAME")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

@Column(name="START_DATE")
public Timestamp getStartDate() {
return startDate;
}
public void setStartDate(Timestamp startDate) {
this.startDate = startDate;
}

@Column(name="STATUS")
public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

@Column(name="TOURNAMENT_ID", nullable = false)
public Long getTournamentId() {
return tournamentId;
}
public void setTournamentId(Long tournamentId) {
this.tournamentId = tournamentId;
}

public Timestamp getUpdts() {
return updts;
}

public void setUpdts(Timestamp updts) {
this.updts = updts;
}
}

When trying to instantiate a tournament, i get an SQL error: ORA-00942: table or view does not exist

The SQL looks like this:
SELECT t1.ID, t1.NAME, t1.STATUS, t1.UPDTS, t1.START_DATE, t1.END_DATE, t1.TOURNAMENT_ID FROM TOURNAMENT_EVENT t0, EVENT t1 WHERE ((t0.Tournament_ID = ?) AND (t1.ID = t0.events_ID))

In other words, it is assumed a join table (TOURNAMENT_EVENT) is used, when i want to join the tables by pointing the EVENT.TOURNAMENT_ID to the TOURNAMENT.ID column.

How do i get around this without using a join table?

Cameron Wallace McKenzie
author and cow tipper
Saloon Keeper

Joined: Aug 26, 2006
Posts: 4968
    
    1

Take a quick look at this example of mine. Both sides of the relation are mapped. It's similar to yours. Mine is a Team has Many Players. Yours is a Tournament has many Events. Just swap the nouns to make it more appropriate to you.





They key parts are the mappings:





It creates this type of a mapping:



Which I think is closer to what you're interested in.

Here's a more detailed description of the mapping. It uses Hibernate behind the scenes, but it uses Hibernate as a JPA implementor.
Mapping One to Many Relationships between Tables with the Java Persistence API (JPA)

-Cameron McKenzie





Bod Toki
Ranch Hand

Joined: Sep 01, 2006
Posts: 95
Hi GoofBall...
(I'm sure you're soon going to get a message from someone in the admin about your name

Please... It's always nice to streamline your code in a post and avoid dumping all of your code in the post. The easier it is to read your post, the faster you'd get a response. Most people don't really have the patience to ward through very long request posts.

That said... Here goes my response to your post:

In entity relationships, there is usually an "owner" of the relationship. The owner table would have a reference column to probably the primary key column of the related entity table.
It turns out that it makes more sense to have the entity on the "many" side to maintain a column holding a reference to the entity on the "one" side. So JPA has it that the "many" side should be the owning side. Which ultimately means that you'd have to have a reference to the "one" entity declared in the "many" entity class.
Relating that to your problem... this means you'd have your code like this:

...That's the way you'd go by it. Sadly if you wanted to have it the other way... i.e. having the Tournament side be the "owning" side of the relationship, you'd have to deal with a JoinTable... and there is no @ManyToOne(mappedBy=""). So you'd most likely have the relationship bidirectional like I have it in the code. I think it works fine this way though... save yourself an extra table.

Have a great time.
Cheers.
Matt S Andersson
Greenhorn

Joined: May 14, 2009
Posts: 4
Thanks for you help, guys. I really appreciate it. I'll test this later today and hope it solves my problem.

Yeah, i considered editing my code before posting, but i wasn't really sure what the problem was so i decide to post all availabled information right away.

And the name - well i wish my parents would have picked a less catchy one, but what can you do... "Toki" means crazy in swedish, by the way ;-)
Paul Sturrock
Bartender

Joined: Apr 14, 2004
Posts: 10336

Goofball Thunderstruck Iii, please check your private messages.


JavaRanch FAQ HowToAskQuestionsOnJavaRanch
Matt S Andersson
Greenhorn

Joined: May 14, 2009
Posts: 4
Hi there, i just though i'd give some feedback on this before we close it.

I tried both suggested solutions and none of them made any difference at all. I finally figured out the Tournament class is missing an "@Table" annotation. I quickly ran my test and confirmed that the error was gone and i haven't had any time to play around with this since. Hopefully i'll work on it tonight.



PS. I also changed my name as suggested.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Why does EJB assume a join table and how do i get around it?
 
Similar Threads
Assigning jsonobject to java class having one to many relationship
JAxb binding problem
retrieving object hierarchy - many-to-one?
Hibernate Select - Criteria with a Date
NamedStoredProcedureQuery gets no result