2013-04-16 9 views
11

Mam następujące klasy Java, który jest również podmiotem Hibernate:java jednostka hibernacji: pozwala na ustalenie powiązanego obiektu zarówno przez id i sam obiekt

@Entity 
@Table(name = "category") 
public class Category { 

    @ManyToOne 
    @JoinColumn(name="parent_id") 
    private Category parent; 

    public Category getParent() { 
     return parent; 
    } 

    public void setParent(Category parent) { 
     this.parent = parent; 
    } 

kategoria reprezentuje węzeł w drzewie kategorii. Wdrażam usługę sieciową, która pozwala na kategorie CRUD. Na przykład interfejs ma możliwość utworzenia węzła drzewa kategorii i przekazuje identyfikator kategorii jako parametr.

Chcę tylko utworzyć nowy obiekt kategorii i zachować go w bazie danych bez pobierania obiektu nadrzędnego. Moja klasa dostawcy danych wygląda następująco:

public void createCategory(int parent_id, String name, CategoryType type) { 
    Category category = new Category(); 
    category.setName(name); 
    // category.setParent(?); <- I don't have this object here 
    // category.setParentId(id); <- but I do have the id 
    category.setType(type); 
    this.categoryDao.save(category); 
} 

Moje pytanie brzmi: co mogę zrobić, aby utworzyć nową kategorię obiektu z parent_id ustawiony jeśli zakładając, że nie będzie wywoływać hibernacji sprowadzić rodzica dla mnie (to byłoby być głupim)? Czy mogę podać metodę setParentId/getParentId dla klasy Category? Jakie byłyby adnotacje hibernacji?

+0

Dlaczego po prostu tego nie spróbujesz? Tak, prawdopodobnie będzie działać. – Magnilex

+0

@MagnusTengdahl Nie mam pojęcia, jak wykonać mapowanie adnotacji ... – ducin

Odpowiedz

17

Hibernate dostarcza metody o nazwie (dość myląco) Session.load() dla tego scenariusza.

Session.load() zwraca lazy proxy z danym identyfikatorem bez wysyłania zapytań do bazy danych (jeśli obiekt z danym identyfikatorem jest już załadowana w obecnym Session, zwraca samego obiektu).

Można użyć tego proxy zainicjować relacje w swoich jednostkach zapisywane:

category.setParent(session.load(Category.class, parent_id)); 

Zauważ, że ten kod nie sprawdza istnienie od Category o podanym id. Jeśli jednak w schemacie DB wystąpi ograniczenie klucza obcego, zostanie wyświetlony błąd naruszenia ograniczenia po przekazaniu nieprawidłowego identyfikatora.

Odpowiednik JPA tej metody nazywa się EntityManager.getReference().

+0

Mam jeden problem tutaj: mój projekt architektoniczny zakłada, że ​​używam BO/DAO (obiekt obiektu biznesowego/dostępu do danych).DAO jest poziomem hibernacji i przechowuje sesję hibernacji. BO (ten w drugim fragmencie kodu) nawet nie wie, że istnieje coś takiego jak sesja hibernacji. Ale - zgodnie z twoim kodem - muszę użyć 'session.load'. Co powinienem zmienić w mojej architekturze? – ducin

+0

Jeśli chcę, aby moja kategoria BO była ogólna, może powinienem podać metodę "setParentId" dla tej kategorii, wywołać ją w BO i przetworzyć na poziomie DAO - co o tym myślisz? – ducin

+0

Myślę, że najlepszą opcją jest dodanie odpowiedniej metody do DAO, coś jak 'Category toReference (long categoryId)'. – axtavt

-1

Można zdefiniować leniwy startowych

@ManyToOne(fetch=FetchType.LAZY) 

odgadnąć kolumna jest pustych, więc nie ma problemu, aby zapisać Kategoria bez rodzica (root)

+0

To nie odpowiada na pytanie. Celem jest stworzenie kategorii z rodzicem. –

1

Jest jeszcze jedno rozwiązanie problemu - przy użyciu domyślnego konstruktor encji, dla której chcesz utworzyć odniesienie i ustawić id i wersję (jeśli jest wersjonowana).

 Constructor<S> c = entityClass.getDeclaredConstructor(); 
     c.setAccessible(true); 

     S instance = c.newInstance(); 
     Fields.set(instance, "id", entityId.getId()); 
     Fields.set(instance, "version", entityId.getVersion()); 
     return instance; 

Możemy użyć takiego podejścia, ponieważ nie używamy leniwy załadunku, ale zamiast tego mieć „widoki” podmiotów, które są wykorzystywane na GUI. To pozwala nam oderwać się od wszystkich połączeń, które Hibernate wykorzystuje do wypełnienia wszystkich gorliwych relacji. Widoki zawsze mają identyfikator i wersję obiektu. W związku z tym możemy wypełnić referencję, tworząc obiekt, który wydaje się być w stanie hibernacji, ponieważ nie jest przejściowy.

Próbowałem zarówno tego podejścia, jak i sesji z session.load(). Oboje działali dobrze. Widzę pewną przewagę w moim podejściu, ponieważ Hibernate nie wycieknie ze swoimi serwerami proxy w innym miejscu kodu. Jeśli nie zostanie poprawnie użyty, po prostu dostanę NPE zamiast wyjątku "nie sesja związana z wątkiem".

Powiązane problemy