Hibernate - rozpoznanie kiedy insert, kiedy update + aktualna tabela w pamieci?

0

Czesc, mam taki troche zawily problem. A wlasciwie sklada sie na niego kilka elementow.

Do programu X przychodza dane. Po ich normalizacji wstawiane sa one do klas typu XEntity. Do programu po jakims czasie t moga przyjsc znow te same dane (obiekt klasy XEntity jest rowny drugiemu XEntity jesli jego pola sa rowne co do wartosci). Klasa XEntity wyglada mniej wiecej tak:

public lass XEntity implements Serializable{

@Id
private int id;
private String name;
private String surname;
private String field1;
private String field2;
private int field3;

//gettery i settery


}

 

Oto moje pytania/problemy:

  1. Zalozmy ze mamy juz liste obiektow typu XEntity gotowa do wstawienia do bazy. Jak (i czy) przy pomocy Hibernate moge to zrobic aby nie wstawial mi rekordow ktore juz istnieja? Nie wyobrazam sobie robic tego na zasadzie ze dla kazdego XEntity bede robila selecta.. saveOrUpdate sie tutaj nie sprawdzi, prawda? Bo z tego co rozumiem to nie dziala tak ze on sobie sprawdza to z baza, tylko chyba przypisuje ten obiekt do sesji i sprawdza z tym co jest w sesji.

  2. Moim kluczem glownym na tabeli x w bazie jest id. "Biznesowym" kluczem jest jednak para imie+nazwisko (nie, nie moge zrobic tak aby byl tam klucz na bazie, ja w ogole nic nie moge robic na bazie). Tzn - jesli mamy XEntity ktore ma:
    imie = jan
    nazwisko = kowalski

to czy ja moge jakos hibernate'a zmusic aby dla kazdego obiektu typu XEntity sprawdzil czy istnieje ta para - jesli istnieje - to by zrobil update (ale tylko jesli ktores z pozostalych pol sie rozni od tego co jest w bazie) lub pominal wstawianie (jesli pozostale pola sa takie same)?

  1. W jaki sposob moge miec w programie hmm.. aktualny stan tabeli? Czy jest w ogole sens robienia czegos takiego? Czy jesli tabela mi sie rozrosnie to program zamuli albo cos?

bede wdzieczna za wszystkie sugestie!

       pzdr,
           misty
0

saveOrUpdate sprawdza, czy dana encja jest już zapisana i wykonuje save/update
Robi to bez odwołania do bazy. Rozpoznaje to po id.

Czy innym jest "taka sama encja" i "ta sam encja".
To, co chcesz zrobić, to unikalność danych i nie ma to nic wspólnego z mechanizmem saveOrUpdate.
Musisz zrobić select + insert/update.

Przy takim podejściu, jeżeli na bazie nie masz constraintów unique, to istnieje niewielka szansa, że 2 równoległe sesje zapiszą encje z takimi samymi danymi.

  1. W jaki sposob moge miec w programie hmm.. aktualny stan tabeli? Czy jest w ogole sens robienia czegos takiego? Czy jesli tabela mi sie rozrosnie to program zamuli albo cos?

Nie da się z dwóch powodów:
-nie starczy pamięci
-inny program może zmodyfikować dane w bazie

0

No co do saveOrUpdate to napisalam w 1szym poscie ze w moim przypadku sie to nie sprawdzi. Nie wierze ze nie da sie tego zrobic. Przeciez jesli mam liste encji do wstawienia - i dla kazdej mialabym wpierw robic selecta by sprawdzic czy istnieje to juz w bazie to bylaby to masakra jakas!

Czekam na dalsze sugestie :)

        pzdr
0

Przyszla mi do glowy taka rzecz (tylko nie mam pojecia czy da sie to zrobic?) - czy ja moglabym w tej klasie Entity oznaczyc jako
@Id dwa pola?

czyli ze oba:

//cos w stylu @Id = imie + nazwisko
private String imie;
private String nazwisko;

? Moze jesli daloby sie cos takiego zrobic to zalatwiloby mi sprawe wtedy zwykle saveOrUpdate? Bo jesli kombinacja imie+nazwisko juz bedzie istniec to zrobi sie update, w przeciwnym wypadku insert..
?

0

To nic Ci nie da.
Przecież hibernate i tak musiałby zrobić select, aby sprawdzić, czy ma zrobić insert, czy update.

Druga sprawa, to klucz główny imie+nazwisko to bardzo zły pomysł.
Znam dwie osoby o tym samym imieniu i nazwisku.

Kluczem powinno być sztuczne id lub np. pesel.

0

jeny.. imie+nazwisko to tylko przyklad!! nie bierz tego tak doslownie :) niech wiec to bedzie field1+field2.

To nic Ci nie da.
Przecież hibernate i tak musiałby zrobić select, aby sprawdzić, czy ma zrobić insert, czy update.

kurcze, no oczywiscie ze tak! o to wlasnie chodzi - ze ma to robic hibernate, gdzies tam pod spodem, w jakiejs ekstra metodzie, rozumiesz? Ja nie chce pisac w swojej aplikacji krok po kroku: select, potem insert lub update. Rozumiesz po co sie tego uzywa, prawda? Zeby samemu nie pisac wielu linii kodu..

Nadal sie z Toba nie zgadzam, tzn wydaje mi sie ze nie masz wiedzy by mi tu pomoc (nie chce Cie urazic). Dokopalam sie do tak zwanych composite-primary keys.

http://j2eereference.com/2011/01/implementing-composit-primary-key-with-jpa-and-hibernate/

Wyglada super! Mam nadzieje ze to bedzie wlasnie to czego szukalam.

     pzdr
0

Composite id nic Ci nie da.

Poczytaj co robi saveOrUpdate:
http://docs.jboss.org/hibernate/orm/3.5/reference/en/html/objectstate.html#objectstate-saveorupdate

Jeżeli bardzo chcesz, to możesz napisać swój interceptor z metodą isTransient (zwracaj true tylko dla tych encji, których nie ma w bazie):
http://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Interceptor.html#isTransient%28java.lang.Object%29

0

hmm, nie mam poki co nawet jak za bardzo tego przetestowac bo wyszedl mi niespodziewane exception. Utworzylam sobie klase ktora jest tym moim compositeId, i w entity oznaczylam go jako @Id. Odpalilam program ze 2 razy dla testow i dostaje:

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:

Ale za kazdym razem program byl zamykany (baza zas jest pusta, ale i tak widac po bledzie ze nie jest to exception z bazy). W applicationContext.xml zas mam:

 	<bean id="hibernateDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

czyli mam: destroy-method="close"

Z tego co rozumiem to powinno mi to wszystko ladnie zamykac po zakonczeniu pracy programu? A wyglada to jakby nie bylo zamykane a ta sesja sobie istnieje. Nie kapuje tego. Masz moze pomysl jak zatem poprawnie zamknac te sesje? By przy ponownym odpaleniu programu nie dostawac takich krzakow?

pzdr,
misty

0
__krzysiek85 napisał(a):

Kluczem powinno być sztuczne id lub np. pesel.

Trochę OT, ale komuś może się przydać.
Pesel jest bardzo złym identyfikatorem. Oprócz sprawdzania czy składa się z 11 cyfr jakakolwiek walidacja jest bezcelowa.

  1. Pesel się może powtórzyć. Miałem z taką sytuacją do czynienia.
  2. Datę urodzenia można zmienić, a zatem i pesel. Więc pesel1 dziś to niekoniecznie ta sama osoba co pesel1 za kilka lat.
  3. Często widywałem pesel w którym suma kontrolna się nie zgadzała.
  4. Pesel może przyjąć 5k urodzeń/płeć/dzień. Możemy tylko czekać na buffer overflow.
  5. Obcokrajowcy nie posiadają numeru pesel, tak jak noworodki i niemowlęta do 6 miesiąca życia. Domyślnie powinni być zapisywani jak 00000000000
0

lool :|

a moze jakis pomysl na moje pytania?

0

ok, dziala mi wszystko. Tak jak myslalam pattern z composite id to byl strzal w 10! I dziala to dokladnie tak jak tego oczekiwalam - z metoda saveOrUpdate. Jedyne o czym trzeba pamietac to by do saveOrUpdate nie podac 2ch obiektow o tych samych compositeId (wtedy rzucany jest wlasnie ten wyjatek o ktorym pisalam wczesniej). I wszystko smiga, super! Polecam linka ktorego podalam wczesniej.

pzdr,
misty

1 użytkowników online, w tym zalogowanych: 0, gości: 1