How to properly set-up Spring Boot & Hibernate using InteliJ? - mysql

As the title suggests I am building a web application using Spring Boot and Hibernate for my data access layer and the development is done on InteliJ IDEA 14.1.2.
My Knowledge
This is my first time using Spring Boot, Hibernate and InteliJ. I have built a few small apps to test Spring Boot and Hibernate, but the complexity difference between those and the one I am building now is a bit bigger.
Environment
Regarding my environment, in case it matters, I am running Windows 7 SP1 64bit, MySQL server 5.6.17, InteliJ 14.1.2 and Ubuntu Server 14.04 on a VirtualBox 4.3.26 VM hosting a Redis 3.0.1 server.
Purpose
The purpose of using the above technologies at this point in time is the storage and retrieval of different entities to a MySQL database (Redis is used only for session externalization and sharing among app instances). In other words, I am building my data access layer.
Database
My complete database schema can be found here:
https://dl.dropboxusercontent.com/u/49544122/so/DB.pdf
Source
My Spring Boot application is the following:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import se.domain.cvs.abstraction.dataaccess.AccountRepository;
import se.domain.cvs.domain.AccountEntity;
#SpringBootApplication
#EnableRedisHttpSession
public class Application implements CommandLineRunner {
#Autowired
AccountRepository repository;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void run(String... strings) throws Exception {
System.out.println("=======================================================");
AccountEntity account = repository.findByEmail("r.franklin#companya.se");
System.out.println("My name is " + account.getFirstName() + " " + account.getLastName());
System.out.println("=======================================================");
}
}
I am using CommandLineRunner interface just to test the bare data access layer without introducing REST endpoints yet.
My configuration is the following in YAML format:
...
# MySQL Database Configuration
spring.datasource:
url: jdbc:mysql://localhost:3306/cvs
username: cvs
password: cvs
driverClassName: com.mysql.jdbc.Driver
spring.jpa:
database: MYSQL
show-sql: true
hibernate.ddl-auto: validate
hibernate.naming-strategy: org.hibernate.cfg.DefaultNamingStrategy
properties.hibernate.dialect: org.hibernate.dialect.MySQL5Dialect
...
The JPA entities are automatically generated with InteliJ and that is where the problems begin. Let's take for example the OrderEntity below (for the sake of brevity I omit some code):
...
#Entity
#Table(name = "order", schema = "", catalog = "cvs")
public class OrderEntity {
...
private int invoiceId;
...
private InvoiceEntity invoiceByInvoiceId;
...
#Basic
#Column(name = "InvoiceID", nullable = false, insertable = false, updatable = false)
public int getInvoiceId() {
return invoiceId;
}
public void setInvoiceId(int invoiceId) {
this.invoiceId = invoiceId;
}
...
#ManyToOne
#JoinColumn(name = "InvoiceID", referencedColumnName = "InvoiceID", nullable = false)
public InvoiceEntity getInvoiceByInvoiceId() {
return invoiceByInvoiceId;
}
public void setInvoiceByInvoiceId(InvoiceEntity invoiceByInvoiceId) {
this.invoiceByInvoiceId = invoiceByInvoiceId;
}
...
}
When trying to run the Spring Boot application I get the following error:
org.hibernate.MappingException: Repeated column in mapping for entity: OrderEntity column: invoiceId (should be mapped with insert="false" update="false")
After doing a little bit of research, I guess the problem is that the invoiceID now has two ways to be set, one through the setInvoiceID() setter and one through the InvoiceEntity object itself that the OrderEntity relates to, which could lead to an inconsistent state. As another user here puts it,
You would do that when the responsibility of creating/udpating the related entity in question isn't in the current entity.
See related post here: Please explain about: insertable=false, updatable=false
Setting the proposed values of the corresponding field (insertable and updateable) to false fixes the error.
My question here is why is this generated the wrong way? My change fixed the error, but I want to make sure that there is no errors in my SQL that lead InteliJ to generate this the wrong way. The complete SQL script can be found here http://pastebin.com/aDguqR1N.
Additionally, when generating the Entities, InteliJ requires a Hibernate config file which I guess Spring Boot generates on its own somewhere else (or uses Java based configuration). Whether I leave it there or delete it, it doesn't seem to affect the app at all. I guess the order taken by SB to read properties overrides it. Is it OK that I just remove it?
Thank you very much for your time and help in advance and sorry for this long post! :)

my advice is to let Spring/Hibernate let generate your db schema for you ( everything including foreign keys and constraints can be generated by Spring.
For me the folloeing approach worked:
in the parent entity(in my case the TblUser):
#OneToMany(targetEntity=TblTracks.class,fetch=FetchType.EAGER,cascade=CascadeType.ALL,mappedBy="tbluser")
private List<TblTracks> tbltracks= new ArrayList<TblTracks>();
where mappedBy points to the Tbluser Entity (private TblUser tbluser) of the child Entity
and in the child entity (in my case TblTracks) like
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="idTblUser",nullable=false)
private TblUser tbluser;

Related

Is it possible to use JDBC Template and JDBC MySQL at the same time?

I’m currently building a simple CRUD based app, and I’m done with the basic stuff, like creating a form with a title, date, description etc, editing or deleting a post etc. So now I’m trying to add an image upload function as well. (I’m using Windows 10 as my OS)
At this moment, I’m studying a tutorial of the following URL
https://www.callicoder.com/spring-boot-file-upload-download-jpa-hibernate-mysql-database-example/
, and when I take a look at
Configuring the Database and Multipart File properties
section, it explains what statements are needed to configure the database and multipart file properties, but when I added the tutorial page’s sample it caused conflict.
The below is how my application.properties file looks like.
(The line “## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties” and after that is the part that I copied and pasted from the tutorial, and above that is the original code before adding the tutorial’s)
spring.datasource.url=jdbc:h2:mem:test
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.h2.console.enabled=true
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url= jdbc:mysql://localhost:3306/file_demo?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username= root
spring.datasource.password= callicoder
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto = update
## Hibernate Logging
logging.level.org.hibernate.SQL= DEBUG
## MULTIPART (MultipartProperties)
# Enable multipart uploads
spring.servlet.multipart.enabled=true
# Threshold after which files are written to disk.
spring.servlet.multipart.file-size-threshold=2KB
# Max file size.
spring.servlet.multipart.max-file-size=200MB
# Max Request Size
spring.servlet.multipart.max-request-size=215MB
The part that’s causing the conflict is the following.
spring.datasource.url=jdbc:h2:mem:test
spring.datasource.username=sa
spring.datasource.url= jdbc:mysql://localhost:3306/file_demo?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username= root
I assume that the reason for the conflict is that I’m trying to use JDBC H2 database and JDBC MySQL at the same time. At first I thought that commenting out my original configuration like below would solve the problem,
#spring.datasource.url=jdbc:h2:mem:test
#spring.datasource.driverClassName=org.h2.Driver
#spring.datasource.username=sa
#spring.h2.console.enabled=true
, but after this I couldn’t run the program probably because there is a part where I use JDBC Templace like below.
[ReportDaoImpl.java]
package com.example.demo.repository;
import java.sql.Timestamp;
#Repository
public class ReportDaoImpl implements ReportDao {
private final JdbcTemplate jdbcTemplate;
#Autowired
public ReportDaoImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
#Override
public List<Report> findAll() {
String sql = "SELECT report_id, title, threat_level, report_date, description, img_path, "
+ "user.user_id, user_name FROM report "
+ "INNER JOIN user ON report.user_id = user.user_id";
List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sql);
……
My biggest question is, how can I integrate the tutorial’s “upload an image” function to my basic CRUD app without causing a conflict in configuration?
Should I give up using JDBC H2 Database and JDBC Template and use something else that is compatible with the JDBC MySQL part that I’m taking from the tutorial? In other words, in order to integrate the tutorial’s image upload function, should I fundamentally restructure my code in ReportDaoImpl.java file (and maybe even other files as well?), or would there be a simple way to resolve the configuration conflict?
You don't have to give away any of your Databases if you intend to use them for absolutely necessary reasons. Spring doesn't DataSourceAutoConfiguration can't differentiate between the two configs in the property file for the simple fact that the property file is a key-value pair map. And hence it would override the configs.
The easiest way to resolve this is:
Create separate keys for different datasources as under:
## Your Primary Data Source
spring.datasource-primary.url=jdbc:h2:mem:test
spring.datasource-primary.driverClassName=org.h2.Driver
spring.datasource-primary.username=sa
spring.h2.console.enabled=true
## Your Secondary Data Source
spring.datasource-secondary.url= jdbc:mysql://localhost:3306/file_demo?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource-secondary.username= root
spring.datasource-secondary.password= callicoder
Add a DataSourceConfig as under
package com.example.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
/**
* Configures the Spring-managed resources for Common Services/Utils.
*/
#Configuration
public class DataSourceConfig {
#Autowired
Environment env;
/**
* Primary DataSource (Meaning the one that is your parent transaction manager)
*/
#Bean
#Primary
public DataSource h2DataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource-primary.driverClassName"));
dataSource.setUrl(env.getProperty("spring.datasource-primary.url"));
dataSource.setUsername(env.getProperty("spring.datasource-primary.username"));
dataSource.setPassword(env.getProperty("spring.datasource-primary.password"));
return dataSource;
}
/**
* #usage Autowire this in your JPA Repositories using
* #Autowired
* JdbcTemplate h2JdbcTemplate;
*/
#Bean
public JdbcTemplate h2JdbcTemplate() {
return new JdbcTemplate(h2DataSource());
}
/**
* Secondary DataSource (Meaning the one that can cause the parent transaction to roll-back on exception)
*/
#Bean
public DataSource mysqlDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource-secondary.driverClassName"));
dataSource.setUrl(env.getProperty("spring.datasource-secondary.url"));
dataSource.setUsername(env.getProperty("spring.datasource-primary.username"));
dataSource.setPassword(env.getProperty("spring.datasource-secondary.password"));
return dataSource;
}
/**
* #usage Autowire this in your JPA Repositories using
* #Autowired
* JdbcTemplate mysqlJdbcTemplate;
*/
#Bean
public JdbcTemplate mysqlJdbcTemplate() {
return new JdbcTemplate(mysqlDataSource());
}
}
Use in right JdbcTemplate in your repository classes
package com.example.demo.repository;
import java.sql.Timestamp;
#Repository
public class ReportDaoImpl implements ReportDao {
//Note the JdbcTemplate variable name here
private final JdbcTemplate myslJdbcTemplate;
#Autowired
//Note the JdbcTemplate variable name here
public ReportDaoImpl(JdbcTemplate myslJdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
#Override
public List<Report> findAll() {
String sql = "SELECT report_id, title, threat_level, report_date, description, img_path, "
+ "user.user_id, user_name FROM report "
+ "INNER JOIN user ON report.user_id = user.user_id";
List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sql);
……
You would need to update the repective JdbcTemplate for all the respective repository classes.
Cheers and happy coding!
You cannot define the same key multiple times in application.properties , one will override the other. That means if you need to use multiple datasources (for MySQL and H2), you cannot relies on the spring.datasource.xxx in application.properties. Instead, define the two DataSource explicitly by yourself. See the official docs for an example.
Also , JdbcTemplate will only be configured if :
Only one DataSource defined
If multiple DataSource are defined but only one DataSource is marked as #Primary, and it will configured just for this #Primary DataSource.
So that means after you define multiple DataSource , you have to mark the H2 one as #Primary such that the JdbcTemplate will be auto configured for it only to ensure that your existing JDBCTempalte related codes still interact with H2 but not MySQL.
By the way, there is no advantages to use multiple database for a simple CRUD app. You will encounter issues if you want to have a transaction which cover the data from multiple databases. I suggest you only choose one for such a simple app.
(Also see my related answer for more detail)

LazyInitializationException trying to get lazy initialized instance

I see the following exception message in my IDE when I try to get lazy initialized entity (I can't find where it is stored in the proxy entity so I can't provide the whole stack trace for this exception):
Method threw 'org.hibernate.LazyInitializationException' exception. Cannot evaluate com.epam.spring.core.domain.UserAccount_$$_jvste6b_4.toString()
Here is a stack trace I get right after I try to access a field of the lazy initialized entity I want to use:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
at com.epam.spring.core.domain.UserAccount_$$_jvstfc9_4.getMoney(UserAccount_$$_jvstfc9_4.java)
at com.epam.spring.core.web.rest.controller.BookingController.refill(BookingController.java:128)
I'm using Spring Data, configured JpaTransactionManager, database is MySql, ORM provider is Hibernate 4. Annotation #EnableTransactionManagement is on, #Transactional was put everywhere I could imagine but nothing works.
Here is a relation:
#Entity
public class User extends DomainObject implements Serializable {
..
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "user_fk")
private UserAccount userAccount;
..
#Entity
public class UserAccount extends DomainObject {
..
#OneToOne(mappedBy = "userAccount")
private User user;
..
.. a piece of configuration:
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(PROP_NAME_DATABASE_DRIVER));
dataSource.setUrl(env.getRequiredProperty(PROP_NAME_DATABASE_URL));
dataSource.setUsername(env.getRequiredProperty(PROP_NAME_DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(PROP_NAME_DATABASE_PASSWORD));
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
entityManagerFactoryBean.setPackagesToScan(env.getRequiredProperty(PROP_ENTITYMANAGER_PACKAGES_TO_SCAN));
entityManagerFactoryBean.setJpaProperties(getHibernateProperties());
return entityManagerFactoryBean;
}
#Bean
public JpaTransactionManager transactionManager(#Autowired DataSource dataSource,
#Autowired EntityManagerFactory entityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
jpaTransactionManager.setDataSource(dataSource);
return jpaTransactionManager;
}
.. and this is how I want to retrieve UserAccount:
#RequestMapping(...)
#Transactional()
public void refill(#RequestParam Long userId, #RequestParam Long amount) {
User user = userService.getById(userId);
UserAccount userAccount = user.getUserAccount();
userAccount.setMoney(userAccount.getMoney() + amount);
}
Hibernate version is 4.3.8.Final, Spring Data 1.3.4.RELEASE and MySql connector 5.1.29.
Please, ask me if something else is needed. Thank you in advance!
Firstly, you should understand that the root of the problem is not a transaction. We have a transaction and a persistent context (session). With #Transactional annotation Spring creates a transaction and opens persistent context. After method is invoked a persistent context becomes closed.
When you call a user.getUserAccount() you have a proxy class that wraps UserAccount (if you don't load UserAccount with User). So when a persistent context is closed, you have a LazyInitializationException during call of any method of UserAccount, for example user.getUserAccount().toString().
#Transactional working only on the userService level, in your case. To get #Transactional work, it is not enough to put the #Transactional annotation on a method. You need to get an object of a class with the method from a Spring Context. So to update money you can use another service method, for example updateMoney(userId, amount).
If you want to use #Transactional on the controller method you need to get a controller from the Spring Context. And Spring should understand, that it should wrap every #Transactional method with a special method to open and close a persistent context. Other way is to use Session Per Request Anti pattern. You will need to add a special HTTP filter.
https://vladmihalcea.com/the-open-session-in-view-anti-pattern/
As #v.ladynev briefly explained, your issue was that you wanted to initialize a lazy relation outside of the persistence context.
I wrote an article about this, you might find it helpful: https://arnoldgalovics.com/lazyinitializationexception-demystified/
For quick solutions despite of performance issues use #transactional in your service
Sample:
#Transactional
public TPage<ProjectDto> getAllPageable(Pageable pageable) {
Page<Project> data = projectRepository.findAll(pageable);
TPage<ProjectDto> response = new TPage<>();
response.setStat(data, Arrays.asList(modelMapper.map(data.getContent(), ProjectDto[].class)));
return response;
}
it will get user details for project manager in the second query.
For more advanced solution, you should read the blog post in the #galovics answer.
I used below to fix
sessionFactory.getObject().getCurrentSession()
Create query and get required object
I was also facing the same error while running my springBoot App.
What is the real issue here?
Please check have you autowired the repository at controller level
If first step is correct then please check where ever you have autowired your JPA repository , it should be a part of #Transactional code.
If not please add #Transactional annotation.It will solve your issue.
I was getting this error:
Method threw 'org.hibernate.LazyInitializationException' exception.
This is because currently there is no session present. Hibernate opens a session and closes it, but for "lazy = true" or "fetch = FetchType.LAZY" such fields are populated by proxies. When you try to find the value for such a field, it will attempt to go to the database using the active session to retrieve the data. If no such session can be found, you get this exception.
You can fix it using "lazy=false" or check whether you have used #Transcational properly (try to use this in your service layer than your data access layer), you can also use
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
OR
#Transactional

Cascading not working in oneToMany, with eclipseLink

I am working with EclipseLink and JPA 2.0.
Those are my 2 entities:
Feeder entity:
#Entity
#Table(name = "t_feeder")
public class Feeder implements Serializable {
private static final long serialVersionUID = 1L;
//Staff
#OneToMany(cascade = CascadeType.ALL, mappedBy = "idAttachedFeederFk")
private Collection<Port> portCollection;
//staff
}
Port entity:
#Entity
#Table(name = "t_port")
public class Port implements Serializable {
//staff
#JoinColumn(name = "id_attached_feeder_fk", referencedColumnName = "id")
#ManyToOne
private Feeder idAttachedFeederFk;
//staff
}
And this is my code:
Feeder f = new Feeder();
//staff
Port p = new Port();
p.setFeeder(f);
save(feeder); //This is the function that calls finally persist.
The probleme is that, only feeder is persisted and not the port. Am I missing something? And specially, in which side should I mention the cascading exactly. Given that in my database, the port table is referencing the feeder one with a foreign key.
EDIT
This simple piece of code worked fine with me:
public static void main(String[] args) {
Address a1 = new Address();
a1.setAddress("madinah 0");
Employee e1 = new Employee();
e1.setName("houssem 0");
e1.setAddressFk(a1);
saveEmplyee(e1);
}
I am not sure why you would expect it to work: you are attempting to save a new instance of Feeder which has no connection whatsoever to the newly created Port.
By adding the Cascade to the #OneToMany and calling save(feeder) Eclipse link would if there were an association:
Insert the record for the Feeder.
Iterate the Port collection and insert the relevant records.
As I have noted however, this new Feeder instance has no Ports associated with it.
With regard to your simple example I assume when you say it works that both the new Address and Employee have been written to the database. This is expected because you have told the Employee about the Address (e1.setAddressFk(a1);) and saved the Employee. Given the presence of the relevant Cascade option then both entities should be written to the database as expected.
Given this it should then be obvious that calling save(port) would work if the necessary cascade option was added to the #ManyToOne side of the relationship.
However if you want to call save(feeder) then you need to fix the data model. Essentially you should always ensure that any in-memory data model is correct at any given point in time, viz. if the first condition below is true then it follows that the second condition must be true.
Port p = new Port();
Feeder feeder = new Feeder();
p.setFeeder(f();
if(p.getFeeder().equals(f){
//true
}
if(f.isAssociatedWithPort(p)){
//bad --> returns false
}
This is obviously best practice anyway but ensuring the correctnes of your in-memory model should mean you do not experience the type of issue you are seeing in a JPA environment.
To ensure the correctness of the in-memory data model you should encapsulate the set/add operations.

Spring Data JPA in two repositories for databases

I want to use spring data jpa repository. And I have to connect to 2 databases. I already found so many similar questions. But most of answers are using Entity manager instead of repository.
For example
#persistenceContext(unitname = "example")
Entitymanager em;
But I want to use repository of spring data jpa. How can I configure in applicationContext.xml?
My 2 databases are MySQL and one is local another is remote server.
You can separate those repositories in different packages. Then its possible to create two DB's configurations with different enity manager factory and transaction manager.
For example first config:
#Configuration
#EnableJpaRepositories(basePackages = "com.firstpackage",
entityManagerFactoryRef = "entityManagerFactoryDb1",
transactionManagerRef = "transactionManagerDb1")
public class DB1Config {
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryDb1() {
...
}
public JpaTransactionManager transactionManagerDb1() {
...
}
public DataSource dataSourceDb11() {
...
}
Second config would be similar.
You didnt put many details in question, but in case you need to switch databases for same repositories ( for example for different locales ) you can use AbstractRoutingDataSource class which will define determineCurrentLookupKey method.

Having trouble getting a Hibernate JUnit test to generate a constraint exception

I'm using Hibernate 4.0.1.Final with a MySQL 5.5 database. I'm writing a Java console app. In a JUnit test, I'm having trouble getting a test to fail. Here's my models under test …
#Entity
#Table(name = "ic_domain")
public class Domain {
#Id
#Column(name = "DOMAIN_ID")
private String domainId;
#OneToOne(fetch = FetchType.EAGER, targetEntity = Organization.class)
#JoinColumn(name = "ORGANIZATION_ID")
private Organization org;
and
#Entity
#Table(name = "ic_organization")
public class Organization {
#Id
#Column(name = "ORGANIZATION_ID")
private String organizationId;
My problem is, in my JUnit test, I'm trying to create a foreign key that doesn't exist, expecting things to fail upon saving, but they never do. Here's the JUnit test
#Test
public void testSaveDomainWithUnmathcedOrg() {
final Organization org = createDummyOrg();
// Create an org id that doesn't exist.
org.setOrganizationId("ZZZZ");
final Domain domain = new Domain();
final String id = UUID.randomUUID().toString().replace("-", "");
domain.setDomainId(id);
domain.setName(org.getName());
domain.setOrg(org);
m_domainDao.saveOrUpdate(domain);
} // testSaveDomainWithUnmatchedOrg
The code of the DAO is
public void saveOrUpdate(final Domain domain) {
final Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(obj);
} // saveOrUpdate
Shouldn't things fail at "session.saveOrUpdate"? How do I make them? I don't want to commit my data in the JUnit test because I don't want to pollute the underlying database with dummy data, but if that is the only way, so be it.
You don't have to commit, but you need to flush the session to trigger execution of SQL statements:
m_domainDao.saveOrUpdate(domain);
sessionFactory.getCurrentSession().flush();
Then you can roll the transaction back if you don't want to pollute the database.
Why do you expect things to fail?
You create a new Domain and save it. Should work as expected.
Domain has a mapping to Organization. You have not stated any #Cascade options so I would guess no insert is made to the Organisation table. Add save-update Cascade options on the one-to-one and I would expect both Domain and Organisation are saved as expected with no issues.
Only issue I can see is if you tried to save the Organisation as the parent Domain would not exist in the database. But then you wouldn't want to do that anyway.
I would suggest maintaining a seperate DB for testing and using something like DBUnit to set up the data for each test run.
http://www.dbunit.org/
I typically use this with Spring's transactional test support and Hibernate's DDL value to to 'create' so the test database automatically updates with every schema change.