Reputation: 122
Tables:
Attributes
: Movie attributes (drama, thriller etc) (has columns: id, name)User
: User in the system (has columns: id, name)Movie
: Has attributes associated (like 'matrix' having 'sci-fi - 60%', 'thriller - 40%' etc) (has columns: id, attrid, fraction) - attrid
is a foreign key into Attributes
Preference
: User's preference for a movie (has columns: id, uid, movieid, rating) - uid
is foreign key into User
and movieid
is foreign key into Movie
.This is the model description I have so far:
User:
@Entity
@Table(name="USER")
public class User extends Model {
@Id
@Column(name = "uid")
public Long uid;
@Column(name = "name")
public String name;
}
Movie Attribute:
@Entity
@Table(name = "MOVIEATTRIBUTE")
public class Attribute extends Model {
@Id
@Column(name = "attrid")
public Long attrid;
@Column(name = "name")
public String name;
@ManyToMany
@JoinColumn(name = "movieid")
public Movie movie;
}
Movie:
@Entity
public class Movie extends Model {
@Id
@Column(name = "movieid")
public Long movieid;
@ManyToMany
@JoinColumn(name = "attrid")
public Attribute attribute;
@Column(name = "rating")
public Integer rating;
}
Preference:
@Entity
public class Preference extends Model {
@Id
@Column(name = "prefid")
public Long prefid;
@ManyToMany
@JoinColumn(name="uid")
public User user;
@ManyToMany
@JoinColumn(name="movieid")
private Movie movie;
@Column(name = "rating")
public Integer rating;
}
I get the following runtime exception: Cannot read annotations for Preference.
What am I missing?
Thanks!
Upvotes: 1
Views: 1368
Reputation: 3922
You have made several mistakes in this code:
You use @ManyToMany annotation incorrectly. You added it to 'Movie movie' field in Attribute class and 'Attribute attribute' field in Movie class. So you can assign only one attribute to movie object and only one movie to attribute. But annotations say that there can be many attributes for single movie and many movies for attribute. If you use @ManyToMany or @OneToMany annotation then you should use collection. So the appropriate relation here should be:
In Movie class:
@OneToMany(mappedBy="movie") public List attributes;
In Attribute class:
@ManyToOne
public Movie movie;
You don't have to specify names for tables and columns. If you omit this they would be the same as class and field names.
I made some correction in your code to make it working:
User class:
@Entity
public class User extends Model {
@Id
public Long id;
public String name;
@OneToMany(mappedBy="user")
public List<Preference> preferences;
}
Movie class:
@Entity
public class Movie extends Model {
@Id
public Long id;
@OneToMany(mappedBy="movie")
public List<Attribute> attributes;
public Integer rating;
public String title;
}
Attribute class:
@Entity
public class Attribute extends Model {
@Id
public Long id;
public String name;
@ManyToOne
public Movie movie;
}
Preferences class:
@Entity
public class Preference extends Model {
@Id
public Long id;
@ManyToOne
public User user;
@OneToOne
public Movie movie;
public Integer rating;
}
Test method:
@Test
public void movieTest () {
FakeApplication app = Helpers.fakeApplication(Helpers.inMemoryDatabase());
Helpers.start(app);
User u = new User();
u.id=1L;
u.name="John";
Movie m = new Movie();
m.id = 1L;
m.title = "Matrix";
m.rating = 5;
Attribute a = new Attribute();
a.id = 1L;
a.name = "Comedy";
a.movie = m;
m.attributes.add(a);
Preference p = new Preference();
p.id = 1L;
p.rating = 10;
p.user=u;
p.movie=m;
Ebean.save(u);
Ebean.save(m);
Ebean.save(a);
Ebean.save(p);
User fu = Ebean.find(User.class, 1L);
Movie fm = Ebean.find(Movie.class, 1L);
Attribute fa = Ebean.find(Attribute.class, 1L);
Preference fp = Ebean.find(Preference.class, 1L);
System.out.println("User: id:"+fu.id+" name:"+fu.name+ " preference_rating:"+fu.preferences.get(0).rating);
System.out.println("Movie: id:" + fm.id+" rating:" + fm.rating + " attrname:"+fm.attributes.get(0).name);
System.out.println("Attribute: id:"+fa.id+" name:"+fa.name);
System.out.println("Preference: id:"+fp.id+" name:"+fp.rating+" username:"+fp.user.name+" movietitle:"+fp.movie.title);
}
Upvotes: 1