2013-04-16 2 views
11

ich folgende Java-Klasse habe, die auch eine Hibernate Einheit ist:Java Hibernate Einheit: erlaubt sowohl von id damit verbundene Ziel gesetzt und das Objekt selbst

@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; 
    } 

Die Kategorie stellt einen Knoten in einem Kategoriebaum. Ich implementiere einen Webservice, der CRUD-Kategorien erlaubt. Zum Beispiel hat die Schnittstelle die Fähigkeit, einen Kategoriebaumknoten zu erstellen, und sie übergibt die Kategorie-ID als einen Parameter.

Ich möchte nur ein neues Category-Objekt erstellen und es in der Datenbank beibehalten, ohne das übergeordnete Objekt abzurufen. Meine Daten-Provider-Klasse sieht wie folgt aus:

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); 
} 

Meine Frage ist: Was kann ich tun, um eine neue Kategorie-Objekt mit dem parent_id wenn unter der Annahme, ich rufe nicht gesetzt erstellen wintern die Eltern für mich zu holen (dies würde dumm sein)? Kann ich eine setParentId/getParentId-Methode für die Category-Klasse bereitstellen? Welche Hibernate Annotations hätte es?

+0

Warum versuchst du es nicht einfach? Ja, es wird wahrscheinlich funktionieren. – Magnilex

+0

@MagnusTengdahl Ich habe keine Ahnung, wie man das Annotationsmapping durchführt ... – ducin

Antwort

17

Hibernate bietet eine Methode namens (ziemlich verwirrend) Session.load() für dieses Szenario.

Session.load() gibt einen Lazy Proxy mit dem angegebenen Bezeichner zurück, ohne die Datenbank abzufragen (wenn das Objekt mit dem angegebenen Bezeichner bereits im aktuellen Session geladen ist, gibt es ein Objekt selbst zurück).

können Sie diesen Proxy verwenden Beziehungen in Ihren Einheiten zu initialisieren gespeichert werden:

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

Beachten Sie, dass dieser Code nicht Existenz von Category mit der angegebenen ID nicht überprüft. Wenn Sie jedoch eine Fremdschlüsseleinschränkung in Ihrem DB-Schema haben, erhalten Sie einen Constraint-Verletzungsfehler, wenn eine ungültige ID übergeben wird.

JPA-Äquivalent dieser Methode heißt EntityManager.getReference().

+0

Ich habe hier ein Problem: Meine Architektur nimmt an, dass ich BO/DAO (Geschäftsobjekt/Datenzugriffsobjekt) verwende.DAO ist der Ruhezustand und hält die Ruhezustand-Sitzung. BO (das in meinem zweiten Code-Snippet) weiß nicht einmal, dass eine Sache wie eine Hibernate-Sitzung existiert. Aber - nach deinem Code - muss ich 'session.load' verwenden. Was sollte ich in meiner Architektur ändern? – ducin

+0

Wenn ich möchte, dass meine Kategorie BO-Klasse generisch ist, sollte ich vielleicht die 'setParentId'-Methode für die Kategorie bereitstellen, sie im BO aufrufen und sie auf der DAO-Ebene verarbeiten - was denkst du darüber? – ducin

+0

Ich denke, dass die beste Option ist, eine entsprechende Methode zu Ihrem DAO hinzuzufügen, etwas wie 'Category toReference (long categoryId)'. – axtavt

-1

können Sie definieren faul init

@ManyToOne(fetch=FetchType.LAZY) 

erraten die Spalte Nullwerte enthalten ist, so dass es kein Problem ist die Kategorie ohne Eltern (root)

+0

Das beantwortet die Frage nicht. Und das Ziel ist gerade, eine Kategorie mit einem Elternteil zu schaffen. –

1

Es gibt eine weitere Lösung für das Problem zu sparen - mit der Standard Konstruktor der Entität, für die eine Referenz erstellt werden soll, und ID und Version (falls versioniert).

 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; 

Wir können einen solchen Ansatz verwenden, weil wir nicht haben, verzögertes Laden verwenden, sondern stattdessen ‚Ansichten‘ von Einheiten, die auf der GUI verwendet werden. Das erlaubt uns, von allen Verbindungen, die Hibernate verwendet, um alle begierigen Beziehungen zu füllen, wegzukommen. Die Ansichten haben immer eine ID und eine Version der Entität. Daher können wir die Referenz füllen, indem wir ein Objekt erstellen, das als "nicht vorübergehend" erscheint.

Ich versuchte sowohl diesen Ansatz als auch den mit session.load(). Sie haben beide gut funktioniert. Ich sehe einen Vorteil in meinem Ansatz, da Hibernate nicht mit seinen Proxies an anderer Stelle im Code ausläuft. Wenn nicht ordnungsgemäß verwendet, erhalte ich nur die NPE anstelle der Ausnahme "keine Sitzung, die an Thread gebunden ist".

Verwandte Themen