Hallo,
als Neuling in Sachen Hibernate habe ich leider noch einige Probleme, die ich beim Studium der Dokumentation leider nicht lösen konnte.
Es gibt in meinem Modell 3 Hauptklassen:
User,
Project,
Message
Mehrere User sind mehreren Projekten zugeordnet, also Many-to-Many.
Mehrere Nachrichten sind einzelnen Projekten zugeordnet, also Many-to-One (aus Message - Sicht).
Mehrere Nachrichten sind einzelnen Usern zugeordnet, also Many-to-One (aus Message - Sicht).
Dies habe ich über Annotations folgendermaßen angegeben:
Message:
Code:
@Id
@GeneratedValue
@Column(name = "id")
private long id; // unique message id
@ManyToOne(cascade = CascadeType.PERSIST)
@NotFound(action = NotFoundAction.IGNORE)
@JoinColumn(name="user_id")
private WebAppUser user; // creator of this message
@ManyToOne(cascade = CascadeType.PERSIST)
@NotFound(action = NotFoundAction.IGNORE)
@JoinColumn(name="project_id")
private WebAppProject project; // project the message is assigned to
@Column(name = "message", nullable = false)
private String message; // message text
@Column(name = "datetime")
private Date datetime; // date/time the message was created
User:
Code:
@Id
@GeneratedValue
@Column(name = "id")
private long id; // unique user id
@Column(name = "username")
private String username; // nickname of the user
@Column(name = "password")
private String password; // password of the user (MD5)
@ManyToMany(fetch = FetchType.EAGER)
@JoinColumn(name="user_id", nullable=false)
private Set<WebAppProject> projects; // a set of projects the user is currently assigned to
Project:
Code:
@Id
@GeneratedValue
@Column(name = "id", updatable = false)
private long id; // unique message id
Nun zum Problem:
Ich möchte alle Nachrichten eines bestimmten Projekts auflisten:
Code:
return (ArrayList<Message>) sessionFactory.getCurrentSession()
.createCriteria(Message.class)
.add(Restrictions.eq("project", currentProject))
.list();
Das Ergebnis: Hibernate erstellt folgende SQL:
Code:
select this_.id as id0_3_, this_.datetime as datetime0_3_, this_.message as message0_3_, this_.project_id as project4_0_3_, this_.user_id as user5_0_3_, webappproj2_.id as id1_0_, webappuser3_.id as id2_1_, webappuser3_.password as password2_1_, webappuser3_.username as username2_1_, projects4_.users_id as users1_5_, webappproj5_.id as projects2_5_, webappproj5_.id as id1_2_ from messages this_ left outer join projects webappproj2_ on this_.project_id=webappproj2_.id left outer join users webappuser3_ on this_.user_id=webappuser3_.id left outer join users_projects projects4_ on webappuser3_.id=projects4_.users_id left outer join projects webappproj5_ on projects4_.projects_id=webappproj5_.id where this_.project_id=?
Das wichtigste:
Hibernate macht einen SELECT über messages -> OK
dann einen LEFT JOIN auf projects über die Projekt-ID der Nachricht -> OK
dann einen LEFT JOIN auf users über die User-ID der Nachricht -> OK
dann einen LEFT JOIN auf users_projects über die User-ID aus users (ein User ist mehreren Projekten zugeordnet) -> OK
und schließlich erneut ein LEFT JOIN auf projects über die Projekt-ID aus users_projects -> NICHT OK!
Daraus erhält man schließlich die Daten einer Nachricht (Tabelle messages) richtig zugeordnet mit Daten aus den Tabellen projects, users.
Dadurch, dass ein User mehreren Projekten zugeordnet ist, holt Hibernate nun auch alle Projekte des Users, das Ergebnis ist also, dass jede Nachricht x-Mal im Ergebnis auftaucht, wobei x die Anzahl aller Projekte ist.
Dabei ist jede Information bis zum LEFT JOIN von 'users' in Ordnung. Danach stehen in den Ergebniszeilen jeweils die Projekt-IDs der Projekte, denen der User zudem zugeordnet ist.
Was mache ich falsch?