Cześć!
Uczę się z kursu Antonio Goncalvesa z Pluralsight o JPA. On tam korzysta z EclipseLink'a, ja korzystam z Hibernate.
Niestety pliki przez niego udostępniane są niekompletne o skrypty sql (które są jakoś generowane, ale dostaję jakieś dziwne wyjątki z którymi długo walczyłem), więc stwierdziłem, że postawię bazę lokalnie z własnymi przykładami.
Korzystam z bazy H2.
Definicję pom.xml
pomijam zakładając, że wszystko jest ok (a połączenie z bazą czy z aplikacji czy z okna Database
w Intellij
odbywa się bezproblemowo).
Mam sobie takie skrypty:
create table CD (
id int primary key AUTO_INCREMENT not null,
title varchar(50) not null ,
description varchar(255) not null,
);
insert into CD (title, description) values ('title', 'description');
oraz
create table MUSICIAN (
id int primary key auto_increment not null ,
first_name varchar(50) not null ,
last_name varchar(50) not null
);
insert into MUSICIAN(first_name, last_name)
values ('FirstName', 'LastName');
Odpowiadające im encje:
// imports ...
@Entity
public class CD {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String description;
@OneToMany
private Set<Musician> musicians = new HashSet<>();
public CD() {
}
public CD(String title, String description, Musician ...musician) {
this.title = title;
this.description = description;
if (musician == null || musician.length == 0) {
throw new IllegalStateException("No musicians declared");
} else {
for (int i = 0; i < musician.length; i++) {
System.out.println(musician[i]);
musicians.add(musician[i]);
}
}
}
// Getters & setters
@Override
public String toString() {
return "CD{" +
"id=" + id +
", title='" + title + '\'' +
", description='" + description + '\'' +
", musician=" + musicians +
'}';
}
}
oraz
// imports ...
@Entity
public class Musician {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
public Musician() {
}
public Musician(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// Getters & setters
@Override
public String toString() {
return "Musician{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Musician musician = (Musician) o;
return Objects.equals(id, musician.id) &&
Objects.equals(lastName, musician.lastName);
}
@Override
public int hashCode() {
return Objects.hash(id, firstName, lastName);
}
}
Przy próbie uruchomienia następującego programu:
// imports ...
public class Main {
public static void main(String[] args) {
EntityManagerFactory factory =
Persistence.createEntityManagerFactory("h2");
EntityManager manager = factory.createEntityManager();
EntityTransaction transaction = manager.getTransaction();
Musician musician = new Musician("ABC", "DEF");
Musician musician1 = new Musician("GHI", "JKL");
transaction.begin();
manager.persist(musician);
manager.persist(musician1);
transaction.commit();
CD cd = new CD("Architects", "New album", musician, musician1);
transaction.begin();
manager.persist(cd);
transaction.commit();
}
}
otrzymuję:
INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Musician{id=2, firstName='ABC', lastName='DEF'}
Musician{id=3, firstName='GHI', lastName='JKL'}
paź 26, 2018 1:27:33 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 42102, SQLState: 42S02
paź 26, 2018 1:27:33 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Tabela "CD_MUSICIAN" nie istnieje
Table "CD_MUSICIAN" not found; SQL statement:
insert into CD_Musician (CD_id, musicians_id) values (?, ?) [42102-197]
paź 26, 2018 1:27:33 AM org.hibernate.internal.ExceptionMapperStandardImpl mapManagedFlushFailure
ERROR: HHH000346: Error during managed flush [org.hibernate.exception.SQLGrammarException: could not prepare statement]
Exception in thread "main" javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:81)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
at com.test.Main.main(Main.java:31)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not prepare statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:65)
... 2 more
Caused by: org.hibernate.exception.SQLGrammarException: could not prepare statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:106)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:182)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareStatement(StatementPreparerImpl.java:78)
at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.buildBatchStatement(AbstractBatchImpl.java:136)
at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.getBatchStatement(AbstractBatchImpl.java:125)
at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1314)
at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:50)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3283)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2479)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:98)
... 1 more
Caused by: org.h2.jdbc.JdbcSQLException: Tabela "CD_MUSICIAN" nie istnieje
Table "CD_MUSICIAN" not found; SQL statement:
insert into CD_Musician (CD_id, musicians_id) values (?, ?) [42102-197]
Czy Hibernate nie powinien sam zająć się tworzeniem odpowiedniej tabeli wraz z kluczami? Czy muszę to robić ręcznie?