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! :)