2016-03-23 10 views
3

Mein Problem null abzurufen ist, dass null in dem Wert des @OneToMany Set organizationMemberCollection abrufen Ruhezustand, wenn die folgende Aufgabe eine Instanz Abrufen:Ruhezustand für OneToMany Sammlung

UserAccount.java:

@Entity 
@Table(name="USER_ACCOUNT") 
public class UserAccount { 

    @Id 
    @Column(name = "id", nullable = false) 
    @SequenceGenerator(name = "generator", sequenceName = "USER_ACCOUNT_id_seq", allocationSize=1) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator") 
    private Long id; 

    @Column(name = "EMAIL", nullable = false) 
    private String email; 

    @Column(name = "PASSWORD_HASH") 
    private String passwordHash; 

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "userAccount") 
    private Set <OrganizationMember> organizationMemberCollection; 

    ... 

    /* 
    * getters and setters 
    */ 
} 

Hier ist das Objekt, das die Zuordnung "besitzt":

OrganizationMember.java:

@Entity 
@Table(name="ORGANIZATION_MEMBER") 
public class OrganizationMember{ 

    @Id 
    @Column(name = "id", nullable = false) 
    @SequenceGenerator(name = "generator", sequenceName = "ORGANIZATION_MEMBER_id_seq", allocationSize=1) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator") 
    private Long id; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "USER_ACCOUNT_ID", nullable = false) 
    private UserAccount userAccount;  

    ... 

    /* 
    * getters and setters 
    */ 
} 

In dieser Anwendung haben wir zwei verschiedene configuations:

  • Produktion, wo Hibernate zu einer PostgreSQL-Datenbank verbunden ist. Hier ist die session Konfiguration für prod:

    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="hibernateProperties"> <props> <prop key="hibernate.jdbc.batch_size">10</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.cglib.use_reflection_optimizer">false</prop> </props> </property> ... </bean>

  • -Test, wo Hibernate conencted ist eine im Speicher HSQLDB Datenbank:

    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.cglib.use_reflection_optimizer">false</prop> <prop key="hibernate.hbm2ddl.auto">create-drop</prop> <prop key="hibernate.cache.use_second_level_cache">false</prop> <prop key="hibernate.cache.use_query_cache">false</prop> </props> </property> ... </bean>

Dieses Problem tritt nur Show up in der Testkonfiguration; In der Produktionskonfiguration läuft alles gut und ich kann die Sammlung bekommen. Wenn ich jedoch ein UserAccount in der Testkonfiguration erhalte, bekomme ich null in der Eigenschaft organizationMemberCollection (kein leeres Set).

Nach einigen Stunden der Recherche durch Google und Hibernate Doc habe ich noch keinen Beitrag zu dem gleichen Thema/Verhalten gefunden, so bin ich ein lillte Bit verloren und Hilfe würde sehr geschätzt werden!

Ich kann natürlich weitere Informationen zur Verfügung stellen, wenn nötig, Danke!

Edit:

-Test higlighting das Problem:

@Test 
@Transactional 
public void testFindUserAccount_OrganizationMemberCollectionFetching() { 

    assertNotNull(userAccountDao.findUserAccount("[email protected]")); //NoProblem 
    assertNotNull(userAccountDao.findUserAccount("[email protected]").getCabinetMemberCollection()); //Fails 

} 

Mit folgenden findUserAccount dao

public UserAccount findUserAccount(String email) { 
    if (email == null) { 
     return null; 
    } 
    UserAccount userAccount = (UserAccount) this.sessionFactory 
      .getCurrentSession().createCriteria(UserAccount.class) 
      .add(Restrictions.eq("email", email).ignoreCase()) 
      .uniqueResult(); 
    if (userAccount == null) { 
     throw new ObjectNotFoundException("UserAccount.notFound"); 
    } else { 
     return userAccount; 
    } 
} 
+0

Sie erhalten eine Null, weil Sie keine OrganisationMemberCollection mit Ihrem Benutzerkonto verknüpft haben. Können Sie den Code Ihres Tests angeben? Vielleicht haben Sie vergessen, setUserAccount-Methode vor dem Speichern der OrganizationMember –

+0

Danke für Ihre schnelle Antwort, ich denke, dass in dieser Situation Hibernate würde mein UserAccount mit einem leeren Set, und nicht den Nullwert zurückgeben, aber vielleicht liege ich falsch. Ich bin ziemlich sicher, dass das OrganizationMember einen Verweis auf das Benutzerkonto hat, da die Datenbank vor den Tests gefüllt ist. Und wenn ich das OrganizationMember abrufen, hat das Objekt, das von Hibernate zurückgegeben wird, einen Verweis auf das UserAccount. – Tom

+0

Sind Sie sicher, dass der Persistenzkontext nicht geschlossen ist, wenn Sie getOrganizationMemberCollection in Ihrem Test aufrufen? Wenn wir den Code vielleicht sehen könnten, könnte es helfen –

Antwort

4

Das Problem ist, dass die Datenbank Bevölkerung und der Test in derselben Transaktion ausgeführt wurden, und Hibernate-Cache nicht zwischen diesen beiden Schritten gereinigt wurde .

Die Konsequenz war, dass Hibernate die Anfrage nicht wirklich an die Datenbank abgefeuert hat, sondern stattdessen den Cache getroffen und das Objekt zurückgegeben hat, ohne irgendeine Verbindung mit der zugeordneten Beziehung einzugehen.

Die möglichen Lösungen sind:

  • die Datenbank in einer anderen Transaktion Bestücken.
  • Reinigen Sie die Sitzung SessionFactory.getCurrentSession().clean(); nach der Population. (Spülen Sie die Sitzung bei Bedarf vorher: SessionFactory.getCurrentSession().flush();).

Jede Möglichkeit wird die nächste Abfrage erzwingen wirklich die Datenbank getroffen, daher tritt die Verbindung und die abgebildete Sammlung werden die gewünschten Daten (oder leer sein enthalten, wenn das kein Ergebnis kommen, aber in jedem Fall die Sammlung wird nicht den Wert null haben).

In meiner Meinung ist die erste Lösung viel besser, da es nicht die gesamte Bevölkerung zurückdrängt, wenn im Test etwas schief geht.

0

Es ist eine faule geladene Sammlung, so überwintert nichts tun, es zu initialisieren ganz normal, dass der Ruhezustand null hier zurückgibt.

Was ich in der Regel tut, ist eine leeres HashSet auf dem Grundstück erklären:

@OneToMany(fetch = FetchType.LAZY, mappedBy = "userAccount") 
private Set <OrganizationMember> organizationMemberCollection = new hashSet<>(); 
+0

Danke für Ihre Antwort, ich glaube FetchType.LAZY bedeutet, dass Hibernate meine Sammlung mit einem Proxy für meine Sammlung initialisiert und nicht den Nullzeiger. – Tom

+0

Eigentlich keine ... that '= new hashSet <>();' sagt Hibernate mit einem Proxy zu initialisieren ... nicht FetchType.LAZY – Pras

+0

Der Versuch es gelöst, die NPE, aber das erhaltene Set ist leer, sieht aus wie Hibernate nicht erkenne diese Zuordnung. Ich verstehe immer noch nicht, warum es an einer realen Datenbank arbeitet, aber nicht an der In-Memory-Datenbank. – Tom