My table(tbl_branch_type) exists in my database. Every other column is there, but I receive this error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [com/example/local/config/LocalDbConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Unable to create unique key constraint (code, bank_type_id) on table tbl_branch_type: database column 'bank_type_id' not found. Make sure that you use the correct column name which depends on the naming strategy in use (it may not be the same as the property name in the entity, especially for relational types)
My BranchType entity is:
#Entity
#Table(
name = "tbl_branch_type",
uniqueConstraints = {
#UniqueConstraint(
name = "uc_branch_type_bank_id_branch_code",
columnNames = {"code", "bank_type_id"})
})
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Getter
#Setter
#EqualsAndHashCode(
callSuper = true,
exclude = {"bankType"})
#ToString(exclude = {"bankType"})
public class BranchType extends Auditing implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_branch_type")
#SequenceGenerator(sequenceName = "seq_branch_type", allocationSize = 1, name = "seq_branch_type")
private Long id;
#NotNull
#Size(min = 1, max = 20)
#Column(name = "code", length = 20, nullable = false)
private String code;
#NotNull
#Size(min = 1, max = 100)
#Column(name = "name", length = 100, nullable = false)
private String name;
#JsonIgnore
#ManyToOne
#JsonIgnoreProperties("")
private BankType bankType;
}
My LocalDbConfiguration class is:
#Configuration
#PropertySource({"classpath:application.yml"})
#EnableJpaRepositories(
basePackages = {"com.example.local.model.dao", "com.example.local.core.auth.repository"})
#EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class LocalDbConfiguration {
#Primary
#Bean(name = "dataSource")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource userDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder, #Qualifier("dataSource") DataSource dataSource) {
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "update");
properties.put("database.platform", "org.hibernate.dialect.Oracle10gDialect");
return builder
.dataSource(dataSource)
.packages(
"com.example.local.model.entity",
"com.example.local.model.mapper",
"com.example.local.core.auth.domain")
.persistenceUnit("localPU")
.properties(properties)
.build();
}
#Primary
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(
#Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource.hikari")
public HikariConfig defaultHikariConfig() {
return new HikariConfig();
}
#Bean
AuditorAware<Long> auditorProvider() {
return new AuditorProviderAware();
}
}
I believe this is the root cause of your problem: database column 'bank_type_id' not found. Try to create that column
I have solved my problem by adding this codes for entityManagerFactory in LocalDbConfiguration.class
properties.put(
"hibernate.physical_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
properties.put(
"hibernate.implicit_naming_strategy",
"org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
Related
I am using Springboot for an app that uses some classes that are managed in another application and stored in another database. My Flight class, which is managed in the current application in a local database, has an attribute of type Aircraft, which is also defined in the current application but is managed in the other application and stored in another database.
The Flight class:
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(schema = "app1")
public class Flight implements Serializable {
#Id
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "flight_sequence"
)
#SequenceGenerator(
name = "flight_sequence",
allocationSize = 1
)
#Column(nullable = false, updatable = false)
private Long id;
private String callsign;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="aircraft_id", nullable=false)
private Aircraft aircraft;
private Date date;
private Operator operator;
private String origin;
private String destination;
}
My Aircraft class:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(schema = "app2")
public class Aircraft implements Serializable {
#Id
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "aircraft_sequence"
)
#SequenceGenerator(
name = "aircraft_sequence",
allocationSize = 1
)
#Column(nullable = false, updatable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="operator_id", nullable=false)
private Operator operator;
private String registration;
private String acType;
}
I wrote a Jpa query in a FlightRepository which uses as a parameter the registration attribute from the Aircraft attribute of the Flight class:
public interface FlightRepository extends JpaRepository<Flight, Long> {
Flight findFirstByDestinationAndAircraftRegistrationOrderByDateDesc(String destination, String registration);
}
but this results in the following exception:
Caused by: org.hibernate.AnnotationException: #OneToOne or #ManyToOne on com.student.application.domain.app1.Flight.aircraft references an unknown entity: com.student.application.domain.app2.Aircraft
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:100)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1750)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processFkSecondPassesInOrder(InFlightMetadataCollectorImpl.java:1694)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1623)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:295)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1460)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1494)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
... 86 more
If I add a #OneToMany annotation to the Aircraft class the problem remains the same. If I remove both the #OneToMany and #ManyToOne annotations, I get a Cannot join to attribute of basic type exception.
These are the configuration classes for the two databases:
#Configuration
#PropertySource({"classpath:application.properties"})
#EnableJpaRepositories(
basePackages = "com.student.application.repository.app1",
entityManagerFactoryRef = "app1EntityManager",
transactionManagerRef = "app1TransactionManager")
public class App1DBConfiguration {
#Autowired
private Environment env;
#Primary
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource app1DataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean app1EntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(app1DataSource());
em.setPackagesToScan(
"com.student.application.domain.app1");
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
env.getProperty("spring.jpa.hibernate.ddl-auto"));
properties.put("hibernate.dialect",
env.getProperty("spring.jpa.properties.hibernate.dialect"));
properties.put("hibernate.dialect.storage_engine",
env.getProperty("spring.jpa.properties.hibernate.dialect.storage_engine"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
public PlatformTransactionManager app1TransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
app1EntityManager().getObject());
return transactionManager;
}
}
#Configuration
#PropertySource({"classpath:application.properties"})
#EnableJpaRepositories(
basePackages = "com.student.application.repository.app2",
entityManagerFactoryRef = "app2EntityManager",
transactionManagerRef = "app2TransactionManager")
public class App2DBConfiguration {
#Autowired
private Environment env;
#Bean
#ConfigurationProperties(prefix = "spring.app2")
public DataSource app2DataSource() {
return DataSourceBuilder.create().build();
}
#Bean
public LocalContainerEntityManagerFactoryBean app2EntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(app2DataSource());
em.setPackagesToScan(
"com.student.application.domain.app2");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
"none");
properties.put("hibernate.implicit_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
properties.put("hibernate.physical_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
em.setJpaPropertyMap(properties);
return em;
}
#Bean
public PlatformTransactionManager app2TransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
app2EntityManager().getObject());
return transactionManager;
}
}
One flight can have just one Aircraft but one aircraft can have more than one flight... so on aircraft you should have
#OneToMany(mappedBy = "Flight") Join column is not needed here
Im assuming you want it to be mapped by flight and have all the info stored in flight table. you could allso join tables and make flight_aircraft table.
annotations On Flight ->
#ManyToOne
#JoinColumn(name="aircraft_id")
How can I filter my list of OneToMany relationships when fetching the parent entity?
Here's my usecase - I have an H2 database in which I'm tracking Products and their Shipment Options. One Product can have many shipment options. Most consumers care only only about the "best" shipment option per country (chosen by some convoluted business logic), while others want to see the best shipment option per country AND per model-number.
I've solved similar scenarios before using the Spring JPA #Where(clause = "childProperty='staticValue'"), however there are many dynamic models and the where clause seems to only support a single static filter.
Any advice / help would be appreciated, everything I've tried so far has failed.
Here are my domain models:
// In file com.my.company.entity.h2.model.Product.java
#Entity
#Table(name = "Product")
public class Product {
#Id
#Column(length = 10)
private int productId;
#LazyCollection(FALSE)
#OneToMany(cascade = REMOVE)
#NotFound(action = IGNORE)
#JoinColumn(name = "productId", referencedColumnName = "productId", insertable = false, updatable = false)
private List<ProductToPrimaryShipmentOption> primaryShipmentOptions = new ArrayList<>();
}
// In file com.my.company.entity.h2.model.relationships.ProductToPrimaryShipmentOption.java:
#Entity
#Table(name = "ProductToPrimaryShipmentOption")
public class ProductToPrimaryShipmentOption {
#EmbeddedId
private ProductAndShipmentOptionIds id;
#Column(columnDefinition = "CHAR", length = 3)
private String country;
#Column(columnDefinition = "CHAR", length = 80)
private String model;
// This flag indicates this is the best shipment option across all the Product's models.
#Column
private boolean best;
#ManyToOne
#JoinColumn(name = "shipmentOptionId", referencedColumnName = "shipmentOptionId", insertable = false, updatable = false)
private ShipmentOption shipmentOption;
}
// In file com.my.company.entity.h2.model.ShipmentOption.java:
#Entity
#Table(name = "ShipmentOption")
public class ShipmentOption {
#Id
#Column(columnDefinition = "CHAR", length = 29)
private String id; // <= concatenated barcode and country
#Column(columnDefinition = "CHAR", length = 80)
private String model;
// Additional Details...
}
I tried using Hibernate filters, but that didn't work - even when activating them in my current session, any repository queries for Products would give me back every Shipment Option, unfiltered.
// In file com.my.company.entity.h2.model.package-info.java:
#FilterDef(
name = "bestFilter",
parameters = #ParamDef(name = "best", type = "boolean")
)
#FilterDef(
name = "modelFilter",
parameters = #ParamDef(name = "model", type = "string")
)
package com.my.company.entity.h2.model;
import org.hibernate.annotations.FilterDef;
import org.hibernate.annotations.ParamDef;
// In file com.my.company.entity.h2.model.relationships.ProductToPrimaryShipmentOption.java:
#Entity
#Table(name = "ProductToPrimaryShipmentOption")
#Filter(
name = "modelFilter",
condition = "model = :model"
)
#Filter(
name = "bestFilter",
condition = "best = :best"
)
public class ProductToPrimaryShipmentOption {...}
// In class com.my.company.infrastructure.repository.config.H2Config.java:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "h2EntityManagerFactory",
transactionManagerRef = "h2TransactionManager",
basePackages = {"com.my.company.infrastructure.repository.h2"})
public class H2Config {
#Bean(name = "h2DataSource")
#ConfigurationProperties(prefix = "spring.h2-datasource")
public DataSource h2DataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "h2EntityManagerFactory")
public EntityManagerFactory h2EntityManagerFactory(
#Qualifier("h2DataSource") DataSource h2DataSource,
#Value("${h2.hibernate.ddl-auto:create}") String ddlAuto,
#Value("${h2.hibernate.dialect:org.hibernate.dialect.H2Dialect}") String dialect,
#Value("${h2.show-sql:false}") boolean showSql,
#Value("${h2.hibernate.generate-statistics:false}") boolean generateStatistics) {
LocalContainerEntityManagerFactoryBean h2EntityManager = new LocalContainerEntityManagerFactoryBean();
h2EntityManager.setDataSource(h2DataSource);
h2EntityManager.setPersistenceUnitName("h2Unit");
h2EntityManager.setPackagesToScan("com.my.company.entity.h2.model");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(showSql);
h2EntityManager.setJpaVendorAdapter(vendorAdapter);
h2EntityManager.setJpaPropertyMap(new HashMap<>() {{
put("hibernate.ddl-auto", ddlAuto);
put("hibernate.dialect", dialect);
put("hibernate.generate_statistics", generateStatistics);
}});
h2EntityManager.afterPropertiesSet();
return h2EntityManager.getObject();
}
#Bean(name = "h2TransactionManager")
public PlatformTransactionManager h2TransactionManager(#Qualifier("h2EntityManagerFactory") EntityManagerFactory h2EntityManagerFactory) {
JpaTransactionManager h2TransactionManager = new JpaTransactionManager();
h2TransactionManager.setEntityManagerFactory(h2EntityManagerFactory);
return h2TransactionManager;
}
}
// In class com.my.company.infrastructure.repository.service.ProductRepositoryService.java:
#Slf4j
#Repository
public class ProductRepositoryService {
#PersistenceContext(unitName = "h2Unit")
private EntityManager entityManager;
public Flux<Product> findAllProducts() {
return Flux.fromIterable(new JpaTableIterable<>((lastProduct, requestSize) -> {
int id = lastProduct == null ? 0 : lastProduct.getId();
return findNextProducts(id, requestSize);
}, productRepository::count));
}
#Transactional(transactionManager = "h2TransactionManager")
protected List<Product> findNextProducts(int id, int requestSize) {
Session session = entityManager.unwrap(Session.class);
Filter filter = session.enableFilter("bestFilter");
filter.setParameter("best", true);
List<Product> products = productRepository
.findAllByIdGreaterThanOrderByIdAsc(id, PageRequest.of(0, requestSize));
session.disableFilter("bestFilter");
return products;
}
}
I tried using Spring Specifications, but again, I'm simply getting back every relationship, unfiltered :(
// In file com.my.company.infrastructure.repository.h2.ProductRepository.java:
#Repository
#Transactional(transactionManager = "h2TransactionManager")
public interface ProductRepository extends JpaRepository<Product, Integer>, JpaSpecificationExecutor<Product> {
//...
}
// In file com.my.company.entity.h2.model.Product_.java:
#StaticMetamodel(Product.class)
public class Product_ {
public static volatile SingularAttribute<Product, Integer> productId;
public static volatile ListAttribute<Product, ProductToPrimaryShipmentOption> primaryShipmentOptions;
}
// In file com.my.company.entity.h2.model.specification.Specifications.java:
public class Specifications {
public static Specification<Product> nextProducts(int lastId) {
return (root, query, builder) -> {
Join<Product, ProductToPrimaryShipmentOption> join = root.join(Product_.primaryPackages, JoinType.LEFT);
return builder.and(
builder.greaterThan(root.get(Product_.id), lastId),
builder.equal(join.get("best"), true);
};
}
}
// In file com.my.company.infrastructure.repository.service.ProductRepositoryService.java:
#Slf4j
#Repository
public class ProductRepositoryService {
#Transactional(transactionManager = "h2TransactionManager")
protected List<Product> findNextProducts(int id, int requestSize) {
return productRepository
.findAll(nextProducts(id), PageRequest.of(0, requestSize))
.getContent();
}
}
UPDATE:
Yet another attempt that failed was using the Hibernate #FilterJoinTable annotation. Still, I see the HQL queries printing in the logs without the filter clause and the collection contains all the unfiltered results.
Here's what I tried:
// In file com.my.company.entity.h2.model.Product.java
#Entity
#Table(name = "Product")
public class Product {
#Id
#Column(length = 10)
private int productId;
#LazyCollection(FALSE)
#ManyToMany(cascade = REMOVE)
#NotFound(action = IGNORE)
#JoinTable(name = "ProductToPrimaryShipmentOption",
joinColumns = #JoinColumn(name = "productId", insertable = false, updatable = false),
inverseJoinColumns = #JoinColumn(name = "shipmentOptionId", insertable = false, updatable = false)
)
#FilterJoinTable(
name = "bestFilter",
condition = "best = :best"
)
private List<ShipmentOption> filteredShipmentOptions = new ArrayList<>();
}
I have an Spring boot application with one entity. I generated an mysql schema and now I am trying to generate a table inside this when my spring boot application is starting I tried this with doing custom configuration classes but it doesnt generate any tables.
Configuration Class:
#Configuration
#PropertySource({"classpath:persistence-multiple-db.properties"})
#EnableJpaRepositories(
basePackages = "com.cbc.coorporateblinddateservice.repositories.meetinsSetting",
entityManagerFactoryRef = "meetingSettingEntityManager",
transactionManagerRef = "meetingSettingTransactionManager"
)
public class MeetingSettingsConfig {
#Autowired
private Environment env;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean meetingSettingEntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(meetingSettingDataSource());
em.setPackagesToScan(
"com.cbc.coorporateblinddateservice.entities.meetinsSetting");
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect",
env.getProperty("hibernate.dialect"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
public DataSource meetingSettingDataSource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setDriverClassName(
env.getProperty("meetingSetting.jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("meetingSetting.jdbc.url"));
dataSource.setUsername(env.getProperty("meetingSetting.jdbc.user"));
dataSource.setPassword(env.getProperty("meetingSetting.jdbc.pass"));
dataSource.setSchema("coorporate_blinddate");
return dataSource;
}
#Primary
#Bean
public PlatformTransactionManager meetingSettingTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
meetingSettingEntityManager().getObject());
return transactionManager;
}
}
Entity:
#Entity
#Table(name = "MeetingsSetting")
public class MeetingsSetting {
#Id
#GeneratedValue
private Long id;
#Column(name = "meeting_name")
private String meetingName;
#Column(name = "meeting_url")
private String meetingUrl;
#Column(name = "meeting_pw")
private String meetingPw;
//
// #OneToMany(mappedBy = "meetingsSetting", cascade = CascadeType.ALL)
// private List<Date> meetingDate = new ArrayList<>();
}
And finally my config.property:
meetingSetting.jdbc.driverClassName=com.mysql.jdbc.Driver
meetingSetting.jdbc.url=jdbc:mysql://localhost:3306/Coorporate_Blinddate?createDatabaseIfNotExist=true&useSSL=true&serverTimezone=UTC
meetingSetting.jdbc.user=root
meetingSetting.jdbc.pass=
I know it takes my config.property because if I enter the wrong user it gives me an error. But know I want to generate the table directly from my entity class.
spring.jpa.hibernate.ddl-auto=create in application.properties file
this requires Spring JPA in your project
The same question has been asked number of times but none of them has solution to my problem.
I have created a hibernate + H2 + Sprinvg mvc project. I am using java based configuration. I have the following beans related to Datasource, SessionFactory and TransactionManager
#Configuration
#ComponentScan(basePackages="org.testpackage")
#EnableWebMvc
#EnableTransactionManagement
public class MyConfiguration extends WebMvcConfigurationSupport {
#Bean(initMethod="start",destroyMethod="stop")
public org.h2.tools.Server h2WebConsonleServer () throws SQLException {
return org.h2.tools.Server.createWebServer("-web","-webAllowOthers","-
webDaemon","-webPort", "8082");
}
#Bean
public DataSource getDataSource() {
return new EmbeddedDatabaseBuilder()
.generateUniqueName(false)
.setName("mytestdb")
.setType(EmbeddedDatabaseType.H2)
.addDefaultScripts()
.setScriptEncoding("UTF-8")
.ignoreFailedDrops(true)
.build();
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(getDataSource());
sessionFactory.setHibernateProperties(hibernateProperties());
sessionFactory.setPackagesToScan(new String[] {"org.testpackage.model"});
return sessionFactory;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(final SessionFactory sessionFactory) {
final HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "validate");
hibernateProperties.setProperty("hibernate.show_sql", "true");
return hibernateProperties;
}
//Some more beans
}
I have the following Entity class
#Entity
#Table(name = "MYTESTDB.TEST_TABLE")
public class User{
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#Column(name = "email", unique = true)
private String email;
public User(int id, String name, String email) {
super();
this.id = id;
this.name = name;
this.email = email;
}
public User() {
}
//Getters and Setters
}
in the DataSource bean I am using addDefaultScripts() and I have 2 sql scripts which create Schema in H2 and insert some predefined value. Which are as follows.
//schema.sql Script
CREATE SCHEMA `MYTESTDB` ;
Drop TABLE IF EXISTS MYTESTDBDB.TEST_TABLE;
CREATE TABLE MYTESTDB.TEST_TABLE (
ID INT NOT NULL PRIMARY KEY,
NAME VARCHAR(50) NOT NULL,
EMAIL VARCHAR(20) NOT NULL,
);
CREATE UNIQUE INDEX ON MYTESTDB.TEST_TABLE (EMAIL)
//data.sql Script
INSERT INTO MYTESTDB.TEST_TABLE(id, name, email)
VALUES ('1', 'Tom', 'tom12#hotmail.com');
If I use hibernate hbm2ddl.auto property value "create" everything works fine, hibernate drops the table and recreate it. I have verified it from the web browser. But if I use "validate" property I get the following error exception
Error creating bean with name 'sessionFactory' defined in org.testPackage.configuration.MYConfiguration: Invocation of init method failed; nested exception is org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [MYTESTDB.TEST_TABLE]
Can anyone please help me to find out the problem?
Its working now. With the help of #Slaw I am able to use "Validate" property.
Use #Table(schema = "MYTESTDB", name = "TEST_TABLE") instead of #Table(name = "MYTESTDB.TEST_TABLE"). But I had to change a bit more in user entity class. Instead of #GeneratedValue annotation I added #GeneratedValue(strategy = GenerationType.IDENTITY). Now everything is working fine.
Thanks #Slaw and #Mykhailo for your valuable time.
There are two entities: parent and child one.
#Entity
#Table(name = "university_group")
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
private String name;
#OneToMany(mappedBy = "group", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Student> students = new HashSet<>();
// getters, setters, constructor, equals+hashcode ...
}
#Entity
#Table(name = "student")
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
private String name;
private String password;
private String email;
#ManyToOne(optional = false)
private Group group;
// getters, setters, constructor, equals+hashcode ...
}
After removing group by em.remove(group) an exception is thrown:
javax.persistence.PersistenceException:
org.hibernate.exception.ConstraintViolationException ...
org.hibernate.engine.jdbc.spi.SqlExceptionHelper: ERROR:
UPDATE or DELETE in table "university_group" breaks foreign key constraint "fk_20su8ubuwt33je1a3ygal7wd6" of table "student"
It seems like hibernate is not deleting students before the group by means of Persistence Provider although it should. Of course, I am able to enable DB cascading, but I would better solve the problem.
Any ideas?
Configured the EntityManager by Spring configs
#Configuration
#EnableTransactionManagement
#PropertySource({"classpath:db.properties"})
public class PersistenceContext {
private static final String BASE_MODEL_SCAN_PACKAGE = "com.chiefhelpsystem.model";
#Value("${db.driverClassName}")
private String dbClassName;
#Value("${db.url}")
private String dbUrl;
#Value("${db.username}")
private String dbUserName;
#Value("${db.password}")
private String dbPassword;
#Bean
DataSource dataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setMaxIdle(20);
ds.setMinIdle(0);
ds.setMaxActive(20);
ds.setDriverClassName(dbClassName);
ds.setUrl(dbUrl);
ds.setUsername(dbUserName);
ds.setPassword(dbPassword);
return ds;
}
#Bean
PlatformTransactionManager transactionManager() {
return new JpaTransactionManager();
}
#Bean(destroyMethod = "destroy")
LocalContainerEntityManagerFactoryBean emf() {
LocalContainerEntityManagerFactoryBean emFactory =
new LocalContainerEntityManagerFactoryBean();
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabase(Database.POSTGRESQL);
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setShowSql(true);
emFactory.setDataSource(dataSource());
emFactory.setPackagesToScan(BASE_MODEL_SCAN_PACKAGE);
emFactory.setJpaVendorAdapter(jpaVendorAdapter);
emFactory.setJpaProperties(jpaProps());
emFactory.setPersistenceProvider(new HibernatePersistenceProvider());
return emFactory;
}
private Properties jpaProps() {
Properties properties = new Properties();
properties.setProperty("format_sql", "true");
return properties;
}
}
Hibernate 4.3.11, Spring 4.3.2
The problem was in the incorrect hachcode() method realization. As soon as I deleted it from sources, the "un-managed deleting" problem has appeared in hibernate TRACE logs and it should be further fixed.