Tomasz Faszyński

Tomasz Faszyński Specjalista ds.
programowania

Temat: Hibernate + adnotacje + relacje

Mam taki kod:


@Entity(name="News")
@Table(name="aplikacja_news")
@Cacheable
@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class News {

@Id
@Column(name="id")
@SequenceGenerator(name = "id_seq", sequenceName = "id")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "id_seq")
private int id;

//@NotNull
@Column(name="id_author")
private Integer id_author;

//@NotEmpty
@Column(name="content")
private String content;

//@NotNull
@Column(name="topic")
private String topic;

private Authors author;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id", nullable = false)
public Authors getAuthor() {
return author;
}

public void setAuthor(Authors author) {
this.author = author;
}

public News() {
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public Integer getId_author() {
return id_author;
}

public void setId_author(Integer id_author) {
this.id_author = id_author;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

public String getTopic() {
return topic;
}

public void setTopic(String topic) {
this.topic = topic;
}
}



@Entity(name="Authors")
@Table(name="aplikacja_authors")
public class Authors {

@Id
@Column(name="id_author")
@SequenceGenerator(name = "id_seq", sequenceName = "id")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "id_seq")
private int id_author;

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

@Column(name="surname")
private String surname;

private Set<News> news;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "author")
@JoinColumn(name = "id_author")
public Set<News> getNews() {
return news;
}

public void setNews(Set<News> news) {
this.news = news;
}

public int getId_author() {
return id_author;
}

public void setId_author(int id_author) {
this.id_author = id_author;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getSurname() {
return surname;
}

public void setSurname(String surname) {
this.surname = surname;
}
}


Łączenie dwóch tabel po author_id. Otrzymuję jednak błąd:


Caused by: org.hibernate.MappingException: Could not determine type for: com.code.domain.Authors, at table: cgi_news, for columns: [org.hibernate.mapping.Column(author)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:306)


Z czego to wynika? Nie konfigurowałem, żadnych xmli. Powinienem?

Bo jeśli dodałem w aplikacja-portlet.xml:

<bean id="hibernateSessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="hibernateDataSource" />


<property name="schemaUpdate" value="true" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.cache.region.factory_class">net.sf.ehcache.hibernate.EhCacheRegionFactory</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>

<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.code.domain.News</value>
<value>com.code.domain.Authors</value>
</list>
</property>

<mapping class="com.code.domain.News" />
<mapping class="com.code.domain.Authors" />
</bean>


To przy <mapping> otrzymuję błąd:

cvc-complex-type.2.4.a: Invalid content was found starting with element 'mapping'. One of '{"http://www.springframework.org/schema/
beans":meta, "http://www.springframework.org/schema/beans":constructor-arg, "http://www.springframework.org/schema/beans":property,
"http://www.springframework.org/schema/beans":qualifier, "http://www.springframework.org/schema/beans":lookup-method, "http://
www.springframework.org/schema/beans":replaced-method, WC[##other:"http://www.springframework.org/schema/beans"]}' is expected.


W czym jest problem?

konto usunięte

Temat: Hibernate + adnotacje + relacje

1. Nie mieszaj deklaracji annotations - albo robisz to nad deklaracją zmiennych, albo robisz to nad getterami. Nigdy to i to.

2. Jeśli jeden autor może mieć wiele newsów, to powinieneś w klasie Author umieścić nad referencją do kolekcji obiektów klasy News (lub nad odpowiednim getterem):
@OneToMany(fetch = FetchType.LAZY, mappedBy = "author")

mappedBy wskazuje zmienną referencyjną, którą powinien posiadać każdy obiekt klasy News. Przy niej hibernate będzie szukał informacji o relacji.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id", nullable = false)

Powinno zatrybić.Andrzej Cichoń edytował(a) ten post dnia 05.09.12 o godzinie 22:49
Tomasz Faszyński

Tomasz Faszyński Specjalista ds.
programowania

Temat: Hibernate + adnotacje + relacje

Andrzej Cichoń:
@OneToMany(fetch = FetchType.LAZY, mappedBy = "author")

mappedBy wskazuje zmienną referencyjną, którą powinien posiadać każdy obiekt klasy News. Przy niej hibernate będzie szukał informacji o relacji.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id", nullable = false)

Powinno zatrybić.

Ok, działa. A jak teraz w widoku jsp wyświetlić w oprócz informacji o news również imię autora?

Mam coś takiego:



<table border="1" width="500px">
<c:forEach var="news" items="${wiadomosci}">
<tr>
<td valign="top" width="50px"><c:out value="NAME AUTORA" /></td>
<td valign="top" width="120px"><c:out value="${news.topic}" /></td>
<td valign="top" width="300px"><c:out value="${news.content}" /></td>
<td valign="top" width="20px">
<a href=
<portlet:actionURL>
<portlet:param name='myaction' value='removeNews' />
<portlet:param name='id' value="${news.id}" />
</portlet:actionURL> ><b>Remove</b></a></td>
</tr>
</c:forEach>

<c:out value="${helloWorldMessage}"/>
</table>


Jak w pole NAME AUTORA wpisać imię autora?
Szymon Lisiecki

Szymon Lisiecki Senior Software
Engineer

Temat: Hibernate + adnotacje + relacje

<td valign="top" width="50px"><c:out value="${news.author.name}" /></td>
Tomasz Faszyński

Tomasz Faszyński Specjalista ds.
programowania

Temat: Hibernate + adnotacje + relacje

Otrzymuję taki błąd, dlaczego?


Caused by: java.lang.NumberFormatException: For input string: "author"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:449)
at java.lang.Integer.parseInt(Integer.java:499)
at javax.el.ArrayELResolver.coerce(ArrayELResolver.java:166)
at javax.el.ArrayELResolver.getValue(ArrayELResolver.java:46)
at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:67)
at org.apache.el.parser.AstValue.getValue(AstValue.java:169)
at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:189)
at org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(PageContextImpl.java:985)
at org.apache.jsp.WEB_002dINF.jsp.helloWorld_jsp._jspx_meth_c_005fout_005f0(helloWorld_jsp.java:239)
at org.apache.jsp.WEB_002dINF.jsp.helloWorld_jsp._jspx_meth_c_005fforEach_005f0(helloWorld_jsp.java:189)
at org.apache.jsp.WEB_002dINF.jsp.helloWorld_jsp._jspService(helloWorld_jsp.java:117)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
... 202 more
10:06:37,860 ERROR [DispatcherPortlet:559] Could not complete request
javax.portlet.PortletException: org.apache.jasper.JasperException: An exception occurred processing JSP page /WEB-INF/jsp/helloWorld.jsp at line 14

11: <table border="1" width="500px">
12: <c:forEach var="news" items="${wiadomosci}">
13: <tr>
14: <td valign="top" width="50px"><c:out value="${news.author.name}" /></td>
15: <td valign="top" width="120px"><c:out value="${news.topic}" /></td>
16: <td valign="top" width="300px"><c:out value="${news.content}" /></td>
17:


Do pobierania danych używam:

return sessionFactory.getCurrentSession().createQuery("from News, Authors").setCacheable(true).list();

Szymon Lisiecki:
<td valign="top" width="50px"><c:out 	[/quote]> value="${news.author.name}" /></td>
Tomasz Faszyński edytował(a) ten post dnia 06.09.12 o godzinie 12:17
Szymon Lisiecki

Szymon Lisiecki Senior Software
Engineer

Temat: Hibernate + adnotacje + relacje

Czy obiekt author nie jest przypadkiem null?

Zobacz co zwraca Ci zapytanie i wyświetl sobie wyniki (np. do logów).

I
...createQuery("from News, Authors")...

Zamieniłbym na
...createQuery("from News")...


Poprzez mapowanie pole author w klasie News zostanie automatycznie zaczytane
Tomasz Faszyński

Tomasz Faszyński Specjalista ds.
programowania

Temat: Hibernate + adnotacje + relacje

Szymon Lisiecki:
Czy obiekt author nie jest przypadkiem null?

Zobacz co zwraca Ci zapytanie i wyświetl sobie wyniki (np. do logów).

I
...createQuery("from News, Authors")...

Zamieniłbym na
...createQuery("from News")...


Poprzez mapowanie pole author w klasie News zostanie automatycznie zaczytane

Ok żadnego błędu nie ma, ale nic nie wyświetla na stronie.
Szymon Lisiecki

Szymon Lisiecki Senior Software
Engineer

Temat: Hibernate + adnotacje + relacje

Zrzuciłeś sobie do logów obiekt zwracany przez zapytanie?

Jeśli tak to czy zapytanie zwraca listę obiektów typu News?

Ile jest takich obiektów?

Czy gdy przeglądasz tabele bazy to widzisz poprawne wpisy?

Czy zanim chciałeś wyświetlić imię autora, na stronie pojawiały się inne dane?Szymon Lisiecki edytował(a) ten post dnia 06.09.12 o godzinie 15:09
Tomasz Faszyński

Tomasz Faszyński Specjalista ds.
programowania

Temat: Hibernate + adnotacje + relacje

Szymon Lisiecki:
Zrzuciłeś sobie do logów obiekt zwracany przez zapytanie?

Jak to zrobić?
Szymon Lisiecki

Szymon Lisiecki Senior Software
Engineer

Temat: Hibernate + adnotacje + relacje

Mniej więcej tak:


List<News> newsList = sessionFactory.getCurrentSession().createQuery("from News").setCacheable(true).list();
if(newsList!=null){
System.out.println("newsList size = " + newsList.size());
for (News n : newsList){
System.out.println(n.getId());
System.out.println(n.getContent());
Author author = n.getAuthor();
author.getId();
author.getName();
} }else{
System.out.println("newsList is null!!!");
}


jeśli masz jakiegoś logera to oczywiście zamiast System.out.println() używasz metod logera np:


logger.debug("newsList size = " + newsList.size());


Natomiast w najbardziej podstawowym przypadku System.out.println też jest ok. To co wyrzucisz za pomocą tej pętelki znajdzie się w pliku logów.
Jeśli używasz tomcata to albo będzie od razu widoczne w konsoli serwera (wersja windows) albo w pliku tomcat/logs/catalina.out (wersja linux). Jeśli używasz logera to plik logów jest tam gdzie sobie skonfigurowałeś.
Tomasz Faszyński

Tomasz Faszyński Specjalista ds.
programowania

Temat: Hibernate + adnotacje + relacje

Szymon Lisiecki:
Mniej więcej tak:


List<News> newsList = sessionFactory.getCurrentSession().createQuery("from News").setCacheable(true).list();
if(newsList!=null){
System.out.println("newsList size = " + newsList.size());
for (News n : newsList){
System.out.println(n.getId());
System.out.println(n.getContent());
Author author = n.getAuthor();
author.getId();
author.getName();
} }else{
System.out.println("newsList is null!!!");
}


Po zrobieniu

Authors author = n.getAuthor();
System.out.println(n.getAuthor());


Okazuje się, że tam jest null, dlaczego?
Szymon Lisiecki

Szymon Lisiecki Senior Software
Engineer

Temat: Hibernate + adnotacje + relacje

Kilka postów wyżej zadałem Ci kilka pytań. Dopóki na nie nie odpowiesz będzie trudno cokolwiek stwierdzić.
Tomasz Faszyński

Tomasz Faszyński Specjalista ds.
programowania

Temat: Hibernate + adnotacje + relacje

No więc:
Szymon Lisiecki:
Zrzuciłeś sobie do logów obiekt zwracany przez zapytanie?

Tak. News pobiera poprawnie, Author jest null.

Jeśli tak to czy zapytanie zwraca listę obiektów typu News?

Tak

Ile jest takich obiektów?

Obiektów jest 10.

Czy gdy przeglądasz tabele bazy to widzisz poprawne wpisy?

Tak widzę poprawne wpisy. Ale dane do tabeli News podałem przez formularz na stronie, a do Authors za pomocą pgAdmin.Czy to może mieć wpływ?

Czy zanim chciałeś wyświetlić imię autora, na stronie pojawiały się inne dane?

Tak.
Szymon Lisiecki

Szymon Lisiecki Senior Software
Engineer

Temat: Hibernate + adnotacje + relacje

Z tego co piszesz to prawdopodobne są 2 przyczyny. Pierwsza to błąd w mapowaniu, 2 to błędne dodanie wpisów do bazy za pomocą pgAdmina.
Jarosław Szczepankiewicz

Jarosław Szczepankiewicz Lead Technical
Consultant

Temat: Hibernate + adnotacje + relacje

3. aktywny cache L2 i obserwacja w krótkim czasie (między inwalidacją L2)

Następna dyskusja:

Spring+Hibernate+Liferay




Wyślij zaproszenie do