ucim ejb3 pa radim jedan mali inf sistem o izvestajima za zaposlene. Koristim javu 1.5.15, radim u netbeansu 6.1 i glassfishu koji je dosao uz njega. I imam oracleovu bazu 10 express, tako da koristim sequence i triggere za auto primary key.
Imam tabele User i Report koje su u vezi tako da jedan korisnik moze da ima vise izvestaja, dok izvestaj pripada tacno jednom korisniku. Tako da tabela Report ima kompozitni primarni kljuc (iduser, idreport). Mapiranje sam uradio tako da koristim anotaciju idclass u entitiju Report, dok entiti User ima List kolekciju userReports:
@OneToMany(cascade = {CascadeType.ALL})
@JoinTable(name="REPORTS_REPORT", joinColumns={@JoinColumn(name="idUser")})
private List <Report> userReports = new ArrayList<Report>();
public List<Report> getUserReports() {
return userReports;
}
public void setUserReports(List<Report> userReports) {
this.userReports = userReports;
}
Za prezentacioni sloj koristim jsf. Imam fajl users.jsp gde datatable komponenta prikazuje korisnike. Svaka vrsta te tabele se zavrsava dugmetom "Izvestaji" koje vodi na novu stranicu userReport.jsp, a koja prikazuje izvestaje izabranog korisnika. Na njoj takodje imam datatable koji prikazuje te izvestaje.
Buduci da nikad ovo nisam radio, cini mi se da je ok da u momentu kada odem na stranicu za izvestaje (za kliknutog korisnika), povucem iz baze sve informacije za tog korisnika, tako da, dokle god sam na stranici za izvestaje, imam jednu promenljivu, selectedUser, koja cuva u sebi sve sto se inace nalazi u bazi za tog korisnika. Ne znam uopste da li je to dobar nacin. Tako sam krenuo da radim da bi mi se forme lakse ucitavale, da ne mora da se pravi round trip do baze svaki put, vec da u memoriji sve cuvam. Ako to tako ne treba da se radi, onda ovo sto sledi mozda i ne vredi.
Uglavnom, datatable na stranici izvestaja vuce svoje podatke iz promenljive reportsModel koja je tipa DataModel, da bih mogao da se sluzim sa getRowData itd. Znaci, u backing beanu imam metod getReportsModel, kao i getFullUser. Evo kako oni izgledaju:
public User getFullUser() {
int idUser = (Integer) Utilities.getSessionObj("idUser");
UserRemote uR = Utilities.getUserRemote();
return uR.getFullUser(idUser);
}
public DataModel getReportsModel() {
if (reportsModel == null) {
reportsModel = new ListDataModel();
}
if (selectedUser == null) {
selectedUser = new User();
selectedUser = getFullUser();
}
reportsModel.setWrappedData(selectedUser.getUserReports());
return reportsModel;
}
Kada se sa stranice izvestaja vracam na roditeljsku o korisnicima, postavio sam da je selectedUser = null, cime sam obezbedio da obrnuto, kada sa korisnika ponovo odem na izvestaje, zaista bude selectedUser = null i onda se izvrsi onaj if deo. U ostalim slucajevima ne treba da mi se izvrsi metod getFullUsers. Inace, on se nalazi u istom backing beanu i ima za zadatak samo da pozove istoimeni metod iz Report session beana koji ce mi ucitati iz baze izabranog korisnika i povuci sve njegove izvestaje:
public User getFullUser(int idUser){
User user = em.find(User.class, idUser);
user.getUserReports().size();
return user;
}
Da bi poziv size() ucitao sve kako treba, moj entiti treba da je managed u persitence contextu. Ovde se desavaju neke cudne stvari :). Recimo, svaki red datatable komponente izvestaja ima dugme "Izbrisi" kojim uspesno izbrisem slog i iz baze i iz selectedUsera:
public String delReport() {
ReportRemote rR = Utilities.getReportRemote();
Report selReport = (Report) reportsModel.getRowData();
selectedUser.getUserReports().remove(selReport);
rR.removeReport(selReport);
return "userReport";
}
Kad odem na to dugme, dogodi se postback, ucita se ponovo stranica, dakle ponovo se pozove metod getReportsModel, selectedUser != null ovaj put, preskoci se if blok, reportsModel se napuni onim sto je ostalo u selectedUser posle brisanja, i to sve lepo izgleda i na ekranu i u bazi, kad proverim bazu kroz oracle manager stvarno je sve ok.
Medjutim, kad ugasim brauzer, pokrenem aplikaciju ponovo i dodjem na izvestaje, ovaj put je selectedUser = null i izvrsi se if blok. Ode se na getFullUser i iz ne znam cega se izvuku podaci koji uopste vise ne postoje u bazi posle prethodnog brisanja. Iz nekog glassfishovog kesha mozda?
Sta bih ovde trebalo da uradim pa da sve lepo proradi? Kada izmenim getFullUser tako da ne koristi tu problematicnu liniju user.getUserReports().size();, vec umesto toga uradim klasican sql kojim povucem sve izvestaje korisnika preko ref integriteta, sve je ok. Ali nije poenta u tome, vec je poenta da koristim bas taj collection atribut iz entitija, ciju sam definiciju naveo na pocetku.