├── .gitignore ├── LICENSE ├── README.md ├── WorkInProgress.md └── jdbc-to-spring-jdbc-to-jpa.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HibernateJPAStepByStep 2 | 3 | ##Entities 4 | 5 | Student 6 | - id 7 | - passport_id 8 | - name 9 | - email 10 | 11 | Passport 12 | - id 13 | - number 14 | - issued_country 15 | 16 | Project 17 | - id 18 | - name 19 | 20 | StudentProject 21 | - id 22 | - student_id 23 | - project_id (Not really needed!!!) 24 | - task_id 25 | 26 | Task 27 | - id 28 | - project_id 29 | - desc 30 | - start_date 31 | 32 | Assumptions 33 | - Student can be in multiple Projects. A Project can have multiple Students. Many to Many. 34 | - Student can have one Passport and vice versa. One to One. 35 | - One Project can have Many Tasks. But one Task is associated with One Project Only. Many to One. 36 | 37 | ##Overview 38 | - Working with both Object-Oriented software and Relational Databases can be cumbersome and time consuming. Development costs are significantly higher due to a paradigm mismatch between how data is represented in objects versus relational databases. 39 | - http://www.agiledata.org/essays/dataModeling101.html and http://en.wikipedia.org/wiki/Data_modeling are good starting points for understanding these data modeling principles. 40 | - Hibernate takes care of the mapping from Java classes to database tables, and from Java data types to SQL data types. 41 | - Also data query and retrieval facilities 42 | - Hibernate’s design goal is to relieve the developer from 95% of common data persistence-related programming tasks 43 | - Hibernate is not a silver bullet. Not meant for application relying heavily on Stored Procedures. 44 | 45 | http://docs.jboss.org/hibernate/orm/5.0/userGuide/en-US/html_single/images/overview.png 46 | 47 | ##History 48 | - JPA 2.0 was released with the specifications of JAVA EE6 => JSR 317. 49 | - JPA 2.1 was released with the specification of JAVA EE7 => JSR 338. 50 | - SessionFactory (org.hibernate.SessionFactory) : A thread-safe (and immutable) representation of the mapping of the application domain model to a database. Acts as a factory for org.hibernate.Session instances. A SessionFactory is very expensive to create; there should be only one SessionFactory for an application for a given database. Maintains services that Hibernate uses across all Sessions such as second level caches, connection pools, transaction system integrations, etc. 51 | - Session (org.hibernate.Session) : A single-threaded, short-lived object conceptually modeling a "Unit of Work"[PoEAA]. Wraps a JDBC java.sql.Connection. Acts as a factory for org.hibernate.Transaction instances. Maintains a generally "repeatable read" persistence context (first level cache) of the application's domain model. 52 | 53 | ##Key Components 54 | 55 | - Entity : A JPA entity class is a POJO , i.e. an ordinary Java class that is annotated as having the ability to represent objects in the database 56 | - EntityManager : Manages the persistence operations on Entities. 57 | - EntityTransaction : One-to-one relationship with EntityManager. For each EntityManager, operations are maintained by EntityTransaction class. 58 | - EntityManagerFactory : Factory class of EntityManager. 59 | - Transaction (org.hibernate.Transaction) TODO - A single-threaded, short-lived object used by the application to demarcate individual physical transaction boundaries. It acts as an abstraction API to isolate the application from the underling transaction system in use (JDBC, JTA, CORBA, etc). 60 | - Domain Model : The POJO should have a no-argument constructor. Both Hibernate and JPA require this. 61 | 62 | ##Important Annotations 63 | 64 | - @Entity : Indicates the class as an entity or a table. 65 | - @Table : Indicates table name. 66 | 67 | - @Id : Identifies the column as a primary key of the Entity. 68 | - @GeneratedValue : Indicates that the column will be auto generated. 69 | - @Transient : Column will not be persisted. 70 | - @Column : Used to specify properties on a Entity Column 71 | 72 | - @JoinColumn : Used to specify the column used in the Join. 73 | 74 | - @ManyToMany Indicates a many-to-many relationship between the join Tables. 75 | - @ManyToOne Indicates a many-to-one relationship between the join Tables. 76 | - @OneToMany Indicates a one-to-many relationship between the join Tables. 77 | - @OneToOne Indicates a one-to-one relationship between the join Tables. 78 | 79 | - @NamedQueries Indicates list of named queries. 80 | - @NamedQuery Indicates a Query using static name. 81 | 82 | # Retrieving Data 83 | The Java Persistence API provides the following methods for querying entities. 84 | - The Java Persistence query language (JPQL) is a simple, string-based language similar to SQL used to query entities and their relationships. 85 | - The Criteria API is used to create typesafe queries using Java programming language APIs to query for entities and their relationships. 86 | 87 | Both JPQL and the Criteria API have advantages and disadvantages: 88 | - Just a few lines long, JPQL queries are typically more concise and more readable than Criteria queries. Developers familiar with SQL will find it easy to learn the syntax of JPQL. 89 | - JPQL named queries can be defined in the entity class using a Java programming language annotation or in the application’s deployment descriptor. Criteria queries are typesafe and therefore don’t require casting, as JPQL queries do. 90 | - JPQL queries are not typesafe, however, and require a cast when retrieving the query result from the entity manager. This means that type-casting errors may not be caught at compile time. JPQL queries don’t support open-ended parameters. 91 | - Criteria queries allow you to define the query in the business tier of the application. Although this is also possible using JPQL dynamic queries, Criteria queries provide better performance because JPQL dynamic queries must be parsed each time they are called. 92 | - The Criteria API is just another Java programming language API and doesn’t require developers to learn the syntax of another query language. Criteria queries are typically more verbose than JPQL queries and require the developer to create several objects and perform operations on those objects before submitting the query to the entity manager. 93 | 94 | ###Find 95 | ###Delete 96 | ##Java Persistence Query language 97 | - JPQL syntax is similar to the syntax of SQL. 98 | - JPQL works with Java Entity Classes 99 | 100 | ``` 101 | 102 | SELECT ... FROM ... 103 | [WHERE ...] 104 | [GROUP BY ... [HAVING ...]] 105 | [ORDER BY ...] 106 | 107 | DELETE FROM ... [WHERE ...] 108 | 109 | UPDATE ... SET ... [WHERE ...] 110 | 111 | MAX 112 | Between A and B 113 | 114 | LIKE 'R%' 115 | ORDER BY columnname ASC 116 | 117 | @NamedQuery(query = "", name = "")\ 118 | entitymanager.createNamedQuery 119 | entitymanager.createQuery("Complete Query"); 120 | 121 | Queries with Parameters 122 | 123 | @NamedQueries({ 124 | @NamedQuery(name="name1", 125 | query="Query1"), 126 | @NamedQuery(name="name2", 127 | query="Query2"), 128 | }) 129 | 130 | 131 | ``` 132 | ##Criteria Query 133 | TODO 134 | 135 | ##Eager and Lazy Fetching 136 | 137 | # Bidirectional relationships 138 | - The inverse side of a bidirectional relationship must refer to its owning side by using the mappedBy element of the @OneToOne, @OneToMany, or @ManyToMany annotation. The mappedBy element designates the property or field in the entity that is the owner of the relationship. 139 | - The many side of many-to-one bidirectional relationships must not define the mappedBy element. The many side is always the owning side of the relationship. 140 | - For one-to-one bidirectional relationships, the owning side corresponds to the side that contains the corresponding foreign key. 141 | - For many-to-many bidirectional relationships, either side may be the owning side. 142 | 143 | ## Cascading 144 | - Entities that use relationships often have dependencies on the existence of the other entity in the relationship. For example, a line item is part of an order; if the order is deleted, the line item also should be deleted. This is called a cascade delete relationship. 145 | - The javax.persistence.CascadeType enumerated type defines the cascade operations that are applied in the cascade element of the relationship annotations. Table 32-1 lists the cascade operations for entities. 146 | 147 | ##Embeddable Classes 148 | - Embeddable classes have the same rules as entity classes but are annotated with the javax.persistence.Embeddable annotation instead of @Entity. 149 | 150 | The following embeddable class, ZipCode, has the fields zip and plusFour: 151 | 152 | @Embeddable 153 | public class ZipCode { 154 | String zip; 155 | String plusFour; 156 | ... 157 | } 158 | 159 | This embeddable class is used by the Address entity: 160 | 161 | @Entity 162 | public class Address { 163 | @Id 164 | protected long id 165 | String street1; 166 | String street2; 167 | String city; 168 | String province; 169 | @Embedded 170 | ZipCode zipCode; 171 | String country; 172 | ... 173 | } 174 | 175 | ## Mapping Strategies : Inheritance Relationships to Database Entitities 176 | You can configure how the Java Persistence provider maps inherited entities to the underlying datastore by decorating the root class of the hierarchy with the annotation javax.persistence.Inheritance. The following mapping strategies are used to map the entity data to the underlying database: 177 | - A single table per class hierarchy 178 | - A table per concrete entity class 179 | - A “join” strategy, whereby fields or properties that are specific to a subclass are mapped to a different table than the fields or properties that are common to the parent class 180 | 181 | 182 | 183 | ##About in28Minutes 184 | - At in28Minutes, we ask ourselves one question everyday. How do we create more effective trainings? 185 | - We use Problem-Solution based Step-By-Step Hands-on Approach With Practical, Real World Application Examples. 186 | - Our success on Udemy and Youtube (2 Million Views & 12K Subscribers) speaks volumes about the success of our approach. 187 | - While our primary expertise is on Development, Design & Architecture Java & Related Frameworks (Spring, Struts, Hibernate) we are expanding into the front-end world (Bootstrap, JQuery, Angular JS). 188 | 189 | ###Our Beliefs 190 | - Best Course are interactive and fun. 191 | - Foundations for building high quality applications are best laid down while learning. 192 | 193 | ###Our Approach 194 | - Problem Solution based Step by Step Hands-on Learning 195 | - Practical, Real World Application Examples. 196 | - We use 80-20 Rule. We discuss 20% things used 80% of time in depth. We touch upon other things briefly equipping you with enough knowledge to find out more on your own. 197 | - We will be developing a demo application in the course, which could be reused in your projects, saving hours of your effort. 198 | - All the code is available on Github, for most steps. 199 | 200 | ###Useful Links 201 | - [Our Website](http://www.in28minutes.com) 202 | - [Youtube Courses](https://www.youtube.com/user/rithustutorials/playlists) 203 | - [Udemy Courses](https://www.udemy.com/user/in28minutes/) 204 | - [Facebook](http://facebook.com/in28minutes) 205 | - [Twitter](http://twitter.com/in28minutes) 206 | - [Google Plus](https://plus.google.com/u/3/110861829188024231119) 207 | 208 | ###Other Courses 209 | - [Spring Framework](https://www.udemy.com/spring-tutorial-for-beginners/) 210 | - [Maven](http://www.in28minutes.com/p/maven-tutorial-for-beginners.html) 211 | - [Eclipse](http://www.in28minutes.com/p/eclipse-java-video-tutorial.html) 212 | - Java 213 | * [Java](https://www.youtube.com/watch?v=Y4ftqcYVh5I&list=PLE0D4634AE2DFA591&index=1) 214 | * [Java Collections](http://www.in28minutes.com/p/java-collections-framework-video.html) 215 | * [Java OOPS Concepts](https://www.udemy.com/learn-object-oriented-programming-in-java/) 216 | - [Design Patterns](http://www.in28minutes.com/p/design-patterns-tutorial.html) 217 | - [JUnit](https://www.udemy.com/junit-tutorial-for-beginners-with-java-examples/) 218 | - [C](https://www.udemy.com/c-tutorial-for-beginners-with-puzzles/) 219 | - [C Puzzles](https://www.udemy.com/c-puzzles-for-beginners/) 220 | - [Javascript](https://www.youtube.com/watch?v=6TZdD-FR6CY) 221 | - [More Courses on Udemy](https://www.udemy.com/user/in28minutes/) 222 | * Java Servlets and JSP : Your first web application in 25 Steps 223 | * Learn Spring MVC in 25 Steps 224 | * Learn Struts in 25 Steps 225 | * Learn Hibernate in 25 Steps 226 | * 10 Steps to Professional Java Developer 227 | - [Java Interview Guide](http://www.in28minutes.com/p/buy-our-java-interview-guide.html) 228 | * Core Java 229 | * Advanced Java 230 | * Spring, Spring MVC 231 | * Struts 232 | * Hibernate 233 | * Design Patterns 234 | * 400+ Questions 235 | * 23 Videos 236 | -------------------------------------------------------------------------------- /WorkInProgress.md: -------------------------------------------------------------------------------- 1 | pom.xml 2 | ``` 3 | 5 | 4.0.0 6 | com.in28minutes 7 | jpa-hibernate-step-by-step 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.2.3.RELEASE 11 | 5.0.6.Final 12 | 13 | 14 | 15 | 16 | org.hibernate 17 | hibernate-entitymanager 18 | ${hibernate.version} 19 | 20 | 21 | 22 | org.springframework 23 | spring-context 24 | ${spring-framework.version} 25 | 26 | 27 | 28 | org.springframework 29 | spring-tx 30 | ${spring-framework.version} 31 | 32 | 33 | 34 | org.springframework 35 | spring-orm 36 | ${spring-framework.version} 37 | 38 | 39 | 40 | org.jboss.spec.javax.transaction 41 | jboss-transaction-api_1.2_spec 42 | 1.0.0.Final 43 | 44 | 45 | 46 | 47 | c3p0 48 | c3p0 49 | 0.9.1.2 50 | 51 | 52 | 53 | org.hsqldb 54 | hsqldb 55 | 2.3.2 56 | 57 | 58 | 59 | log4j 60 | log4j 61 | 1.2.14 62 | runtime 63 | 64 | 65 | 66 | 67 | junit 68 | junit 69 | 4.12 70 | test 71 | 72 | 73 | 74 | org.springframework 75 | spring-test 76 | ${spring-framework.version} 77 | test 78 | 79 | 80 | 81 | 82 | ``` 83 | Readme.md 84 | ``` 85 | - Working with both Object-Oriented software and Relational Databases can be cumbersome and time consuming. Development costs are significantly higher due to a paradigm mismatch between how data is represented in objects versus relational databases. 86 | - http://www.agiledata.org/essays/dataModeling101.html and http://en.wikipedia.org/wiki/Data_modeling are good starting points for understanding these data modeling principles. 87 | - Hibernate takes care of the mapping from Java classes to database tables, and from Java data types to SQL data types. 88 | - Also data query and retrieval facilities 89 | - Hibernate’s design goal is to relieve the developer from 95% of common data persistence-related programming tasks 90 | - Hibernate is not a silver bullet. Not meant for application relying heavily on Stored Procedures. 91 | 92 | http://docs.jboss.org/hibernate/orm/5.0/userGuide/en-US/html_single/images/overview.png 93 | 94 | SessionFactory (org.hibernate.SessionFactory) 95 | A thread-safe (and immutable) representation of the mapping of the application domain model to a database. Acts as a factory for org.hibernate.Session instances. 96 | 97 | A SessionFactory is very expensive to create; there should be only one SessionFactory for an application for a given database. Maintains services that Hibernate uses across all Sessions such as second level caches, connection pools, transaction system integrations, etc. 98 | 99 | Session (org.hibernate.Session) 100 | A single-threaded, short-lived object conceptually modeling a "Unit of Work"[PoEAA]. 101 | 102 | Wraps a JDBC java.sql.Connection. Acts as a factory for org.hibernate.Transaction instances. Maintains a generally "repeatable read" persistence context (first level cache) of the application's domain model. 103 | 104 | Transaction (org.hibernate.Transaction) 105 | A single-threaded, short-lived object used by the application to demarcate individual physical transaction boundaries. It acts as an abstraction API to isolate the application from the underling transaction system in use (JDBC, JTA, CORBA, etc). 106 | 107 | Domain Model 108 | The POJO should have a no-argument constructor. Both Hibernate and JPA require this. 109 | 110 | 111 | Hibernate Bean Validation 112 | 113 | Bidirectional relationships must follow these rules. 114 | - The inverse side of a bidirectional relationship must refer to its owning side by using the mappedBy element of the @OneToOne, @OneToMany, or @ManyToMany annotation. The mappedBy element designates the property or field in the entity that is the owner of the relationship. 115 | - The many side of many-to-one bidirectional relationships must not define the mappedBy element. The many side is always the owning side of the relationship. 116 | - For one-to-one bidirectional relationships, the owning side corresponds to the side that contains the corresponding foreign key. 117 | - For many-to-many bidirectional relationships, either side may be the owning side. 118 | 119 | Entities that use relationships often have dependencies on the existence of the other entity in the relationship. For example, a line item is part of an order; if the order is deleted, the line item also should be deleted. This is called a cascade delete relationship. 120 | The javax.persistence.CascadeType enumerated type defines the cascade operations that are applied in the cascade element of the relationship annotations. Table 32-1 lists the cascade operations for entities. 121 | 122 | Embeddable classes have the same rules as entity classes but are annotated with the javax.persistence.Embeddable annotation instead of @Entity. 123 | 124 | The following embeddable class, ZipCode, has the fields zip and plusFour: 125 | 126 | @Embeddable 127 | public class ZipCode { 128 | String zip; 129 | String plusFour; 130 | ... 131 | } 132 | This embeddable class is used by the Address entity: 133 | 134 | @Entity 135 | public class Address { 136 | @Id 137 | protected long id 138 | String street1; 139 | String street2; 140 | String city; 141 | String province; 142 | @Embedded 143 | ZipCode zipCode; 144 | String country; 145 | ... 146 | } 147 | 148 | 149 | You can configure how the Java Persistence provider maps inherited entities to the underlying datastore by decorating the root class of the hierarchy with the annotation javax.persistence.Inheritance. The following mapping strategies are used to map the entity data to the underlying database: 150 | 151 | A single table per class hierarchy 152 | 153 | A table per concrete entity class 154 | 155 | A “join” strategy, whereby fields or properties that are specific to a subclass are mapped to a different table than the fields or properties that are common to the parent class 156 | 157 | 158 | The Java Persistence API provides the following methods for querying entities. 159 | 160 | The Java Persistence query language (JPQL) is a simple, string-based language similar to SQL used to query entities and their relationships. See Chapter 34, The Java Persistence Query Language for more information. 161 | 162 | The Criteria API is used to create typesafe queries using Java programming language APIs to query for entities and their relationships. See Chapter 35, Using the Criteria API to Create Queries for more information. 163 | 164 | Both JPQL and the Criteria API have advantages and disadvantages. 165 | 166 | Just a few lines long, JPQL queries are typically more concise and more readable than Criteria queries. Developers familiar with SQL will find it easy to learn the syntax of JPQL. JPQL named queries can be defined in the entity class using a Java programming language annotation or in the application’s deployment descriptor. JPQL queries are not typesafe, however, and require a cast when retrieving the query result from the entity manager. This means that type-casting errors may not be caught at compile time. JPQL queries don’t support open-ended parameters. 167 | 168 | Criteria queries allow you to define the query in the business tier of the application. Although this is also possible using JPQL dynamic queries, Criteria queries provide better performance because JPQL dynamic queries must be parsed each time they are called. Criteria queries are typesafe and therefore don’t require casting, as JPQL queries do. The Criteria API is just another Java programming language API and doesn’t require developers to learn the syntax of another query language. Criteria queries are typically more verbose than JPQL queries and require the developer to create several objects and perform operations on those objects before submitting the query to the entity manager. 169 | ``` 170 | src\main\java\com\in28minutes\hibernate\model\Passport.java 171 | ``` 172 | package com.in28minutes.hibernate.model; 173 | 174 | import javax.persistence.Column; 175 | import javax.persistence.Entity; 176 | import javax.persistence.GeneratedValue; 177 | import javax.persistence.GenerationType; 178 | import javax.persistence.Id; 179 | 180 | @Entity 181 | public class Passport { 182 | @Id 183 | @GeneratedValue(strategy = GenerationType.IDENTITY) 184 | private long id; 185 | 186 | private String number; 187 | 188 | @Column(name = "issued_country") 189 | private String issuedCountry; 190 | 191 | public Passport() { 192 | super(); 193 | } 194 | 195 | public Passport(long id, String number, String issuedCountry) { 196 | super(); 197 | this.id = id; 198 | this.number = number; 199 | this.issuedCountry = issuedCountry; 200 | } 201 | 202 | public long getId() { 203 | return id; 204 | } 205 | 206 | public void setId(long id) { 207 | this.id = id; 208 | } 209 | 210 | public String getNumber() { 211 | return number; 212 | } 213 | 214 | public void setNumber(String number) { 215 | this.number = number; 216 | } 217 | 218 | public String getIssuedCountry() { 219 | return issuedCountry; 220 | } 221 | 222 | public void setIssuedCountry(String issuedCountry) { 223 | this.issuedCountry = issuedCountry; 224 | } 225 | 226 | @Override 227 | public String toString() { 228 | return "Passport [id=" + id + ", number=" + number + ", issuedCountry=" + issuedCountry + "] "; 229 | } 230 | } 231 | ``` 232 | src\main\java\com\in28minutes\hibernate\model\Project.java 233 | ``` 234 | package com.in28minutes.hibernate.model; 235 | 236 | public class Project { 237 | private int id; 238 | private String name; 239 | 240 | public int getId() { 241 | return id; 242 | } 243 | 244 | public void setId(int id) { 245 | this.id = id; 246 | } 247 | 248 | public String getName() { 249 | return name; 250 | } 251 | 252 | public void setName(String name) { 253 | this.name = name; 254 | } 255 | 256 | @Override 257 | public String toString() { 258 | return "Project [id=" + id + ", name=" + name + "]"; 259 | } 260 | } 261 | ``` 262 | src\main\java\com\in28minutes\hibernate\model\Student.java 263 | ``` 264 | package com.in28minutes.hibernate.model; 265 | 266 | import javax.persistence.Entity; 267 | import javax.persistence.GeneratedValue; 268 | import javax.persistence.GenerationType; 269 | import javax.persistence.Id; 270 | import javax.persistence.NamedQuery; 271 | import javax.persistence.OneToOne; 272 | import javax.persistence.Table; 273 | 274 | @Entity 275 | @Table(name = "Student") 276 | @NamedQuery(query = "select s from Student s", name = "find all students") 277 | public class Student { 278 | 279 | @Id 280 | @GeneratedValue(strategy = GenerationType.IDENTITY) 281 | private long id; 282 | 283 | private String name; 284 | 285 | @OneToOne 286 | private Passport passport; 287 | 288 | private String email; 289 | 290 | public long getId() { 291 | return id; 292 | } 293 | 294 | public void setId(long id) { 295 | this.id = id; 296 | } 297 | 298 | public String getName() { 299 | return name; 300 | } 301 | 302 | public void setName(String name) { 303 | this.name = name; 304 | } 305 | 306 | public Passport getPassport() { 307 | return passport; 308 | } 309 | 310 | public void setPassportId(Passport passport) { 311 | this.passport = passport; 312 | } 313 | 314 | public String getEmail() { 315 | return email; 316 | } 317 | 318 | public void setEmail(String email) { 319 | this.email = email; 320 | } 321 | 322 | @Override 323 | public String toString() { 324 | return "Student [id=" + id + ", name=" + name + ", passport=" + passport + ", email=" + email + "]"; 325 | } 326 | 327 | } 328 | ``` 329 | src\main\java\com\in28minutes\hibernate\model\Task.java 330 | ``` 331 | package com.in28minutes.hibernate.model; 332 | 333 | import java.util.Date; 334 | 335 | public class Task { 336 | private int id; 337 | private int projectId; 338 | private Date startDate; 339 | private String desc; 340 | 341 | public int getId() { 342 | return id; 343 | } 344 | 345 | public void setId(int id) { 346 | this.id = id; 347 | } 348 | 349 | public int getProjectId() { 350 | return projectId; 351 | } 352 | 353 | public void setProjectId(int projectId) { 354 | this.projectId = projectId; 355 | } 356 | 357 | public Date getStartDate() { 358 | return startDate; 359 | } 360 | 361 | public void setStartDate(Date startDate) { 362 | this.startDate = startDate; 363 | } 364 | 365 | public String getDesc() { 366 | return desc; 367 | } 368 | 369 | public void setDesc(String desc) { 370 | this.desc = desc; 371 | } 372 | 373 | @Override 374 | public String toString() { 375 | return "Task [id=" + id + ", projectId=" + projectId + ", startDate=" + startDate + ", desc=" + desc + "]"; 376 | } 377 | 378 | } 379 | ``` 380 | src\main\java\com\in28minutes\hibernate\service\StudentRepository.java 381 | ``` 382 | package com.in28minutes.hibernate.service; 383 | 384 | import java.util.List; 385 | 386 | import javax.persistence.EntityManager; 387 | import javax.persistence.PersistenceContext; 388 | import javax.persistence.Query; 389 | 390 | import org.springframework.stereotype.Repository; 391 | 392 | import com.in28minutes.hibernate.model.Student; 393 | 394 | @Repository 395 | public class StudentRepository { 396 | 397 | @PersistenceContext 398 | private EntityManager entityManager; 399 | 400 | public Student getStudent(final long id) { 401 | return entityManager.find(Student.class, id); 402 | } 403 | 404 | public Student insertStudent(Student student) { 405 | if (student.getPassport() != null) 406 | entityManager.merge(student.getPassport()); 407 | return entityManager.merge(student); 408 | } 409 | 410 | public Student updateStudent(Student student) { 411 | entityManager.merge(student); 412 | return student; 413 | } 414 | 415 | public Student retrieveStudentsFrom(String string) { 416 | return null; 417 | } 418 | 419 | public List getAllStudents() { 420 | Query query = entityManager.createNamedQuery("find all students"); 421 | return query.getResultList(); 422 | } 423 | } 424 | ``` 425 | src\main\java\com\in28minutes\hibernate\service\StudentService.java 426 | ``` 427 | package com.in28minutes.hibernate.service; 428 | 429 | import java.util.List; 430 | 431 | import javax.transaction.Transactional; 432 | 433 | import org.springframework.beans.factory.annotation.Autowired; 434 | import org.springframework.stereotype.Service; 435 | 436 | import com.in28minutes.hibernate.model.Student; 437 | 438 | @Service 439 | public class StudentService { 440 | 441 | @Autowired 442 | StudentRepository service; 443 | 444 | @Transactional 445 | public Student insertStudent(Student student) { 446 | return service.insertStudent(student); 447 | } 448 | 449 | @Transactional 450 | public Student getStudent(final long id) { 451 | return service.getStudent(id); 452 | } 453 | 454 | @Transactional 455 | public Student updateStudent(Student student) { 456 | return service.updateStudent(student); 457 | } 458 | 459 | @Transactional 460 | public Student retrieveIndianStudents() { 461 | return service.retrieveStudentsFrom("India"); 462 | } 463 | 464 | @Transactional 465 | public List getAllStudents() { 466 | return service.getAllStudents(); 467 | } 468 | 469 | } 470 | ``` 471 | src\main\resources\config\data.sql 472 | ``` 473 | INSERT INTO passport VALUES (201,'L1234567','India'); 474 | INSERT INTO passport VALUES (202,'L1234568','India'); 475 | 476 | INSERT INTO student VALUES (101,201,'Jane', 'jane@doe.com'); 477 | INSERT INTO student VALUES (102,202,'Doe', 'doe@doe.com'); 478 | 479 | INSERT into project VALUES (301, 'In28Minutes Project 1'); 480 | 481 | INSERT into task VALUES (401, 301, 'Create JPA Tutorial','2015-12-24'); 482 | 483 | INSERT into student_project VALUES (501, 101, 301, 401); 484 | ``` 485 | src\main\resources\config\database.properties 486 | ``` 487 | #HSQL in-memory db 488 | db.driver=org.hsqldb.jdbcDriver 489 | db.url=jdbc:hsqldb:mem:firstdb 490 | db.username=sa 491 | db.password= 492 | ``` 493 | src\main\resources\config\hibernate.properties 494 | ``` 495 | hibernate.dialect=org.hibernate.dialect.HSQLDialect 496 | hibernate.show_sql=false 497 | hibernate.format_sql=false 498 | hibernate.use_sql_comments=true 499 | ``` 500 | src\main\resources\config\schema.sql 501 | ``` 502 | CREATE TABLE student ( 503 | id int IDENTITY NOT NULL PRIMARY KEY, 504 | passport_id int NULL, 505 | name varchar(32) NOT NULL, 506 | email varchar(32) NOT NULL 507 | ); 508 | 509 | CREATE TABLE passport ( 510 | id int IDENTITY NOT NULL PRIMARY KEY, 511 | number varchar(32) NOT NULL, 512 | issued_country varchar(32) NOT NULL 513 | ); 514 | 515 | alter table student add constraint student_passport_fk foreign key (passport_id) references passport(id); 516 | 517 | 518 | CREATE TABLE project ( 519 | id int IDENTITY NOT NULL PRIMARY KEY, 520 | name varchar(32) NOT NULL 521 | ); 522 | 523 | CREATE TABLE task ( 524 | id int IDENTITY NOT NULL PRIMARY KEY, 525 | project_id int NOT NULL, 526 | desc varchar(216) NOT NULL, 527 | start_date date DEFAULT NULL 528 | ); 529 | 530 | alter table task add constraint task_project_fk foreign key (project_id) references project(id); 531 | 532 | CREATE TABLE student_project ( 533 | id int IDENTITY NOT NULL PRIMARY KEY, 534 | student_id int NOT NULL, 535 | project_id int NOT NULL, 536 | task_id int NOT NULL 537 | ); 538 | 539 | alter table student_project add constraint student_project_student_fk foreign key (student_id) references student(id); 540 | alter table student_project add constraint student_project_project_fk foreign key (project_id) references project(id); 541 | alter table student_project add constraint student_project_task_fk foreign key (task_id) references task(id); 542 | ``` 543 | src\main\resources\log4j.properties 544 | ``` 545 | log4j.rootLogger=info, stdout 546 | 547 | #log messages to stdout 548 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 549 | log4j.appender.stdout.Target=System.out 550 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 551 | log4j.appender.stdout.layout.ConversionPattern= %d{dd/MM/yyyy HH:mm} [%-5p] %c:%L - %m%n 552 | 553 | # Log everything. Good for troubleshooting 554 | log4j.logger.org.hibernate=debug 555 | log4j.logger.org.springframework=debug 556 | log4j.javax.servlet=info 557 | 558 | # Log all JDBC parameters 559 | log4j.logger.org.hibernate.type=all 560 | ``` 561 | src\main\resources\META-INF\persistence.xml 562 | ``` 563 | 564 | 565 | 567 | 568 | org.hibernate.jpa.HibernatePersistenceProvider 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | ``` 579 | src\main\resources\META-INF\spring\spring-context.xml 580 | ``` 581 | 582 | 583 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | ``` 637 | src\test\java\com\in28minutes\hibernate\service\StudentServiceTest.java 638 | ``` 639 | package com.in28minutes.hibernate.service; 640 | 641 | import static org.junit.Assert.assertEquals; 642 | import static org.junit.Assert.assertNotNull; 643 | 644 | import org.junit.After; 645 | import org.junit.Test; 646 | import org.junit.runner.RunWith; 647 | import org.springframework.beans.factory.annotation.Autowired; 648 | import org.springframework.stereotype.Service; 649 | import org.springframework.test.context.ContextConfiguration; 650 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 651 | import org.springframework.transaction.annotation.Transactional; 652 | 653 | import com.in28minutes.hibernate.model.Passport; 654 | import com.in28minutes.hibernate.model.Student; 655 | 656 | @RunWith(SpringJUnit4ClassRunner.class) 657 | @ContextConfiguration(locations = { "classpath:META-INF/spring/spring-context.xml" }) 658 | @Service 659 | public class StudentServiceTest { 660 | 661 | @Autowired 662 | private StudentService service; 663 | 664 | @Test 665 | @Transactional 666 | public void testGetStudent() { 667 | Student student = service.getStudent(101); 668 | System.out.println(student); 669 | assertNotNull(student); 670 | assertEquals(101, student.getId()); 671 | } 672 | 673 | @Test 674 | @Transactional 675 | public void testGetStudent_GettingAPassport() { 676 | Student student = service.getStudent(101); 677 | assertNotNull(student.getPassport()); 678 | assertEquals(201, student.getPassport().getId()); 679 | } 680 | 681 | @Test 682 | @Transactional 683 | public void testUpdateStudent() { 684 | Student student = service.getStudent(101); 685 | student.setName("Doe v2"); 686 | Student insertedStudent = service.updateStudent(student); 687 | Student retrievedStudent = service.getStudent(insertedStudent.getId()); 688 | System.out.println(student); 689 | assertNotNull(retrievedStudent); 690 | } 691 | 692 | @Test 693 | public void testInsertStudent() { 694 | Passport passport = new Passport(202, "L12344432", "India"); 695 | Student student = createStudent("dummy@dummy.com", "Doe", passport); 696 | Student insertedStudent = service.insertStudent(student); 697 | Student retrievedStudent = service.getStudent(insertedStudent.getId()); 698 | assertNotNull(retrievedStudent); 699 | } 700 | 701 | @Test 702 | public void testInsertStudent_withoutPassport() { 703 | Student student = createStudent("dummy@dummy.com", "Doe", null); 704 | Student insertedStudent = service.insertStudent(student); 705 | Student retrievedStudent = service.getStudent(insertedStudent.getId()); 706 | assertNotNull(retrievedStudent); 707 | } 708 | 709 | private Student createStudent(String email, String name, Passport passport) { 710 | Student student = new Student(); 711 | student.setEmail(email); 712 | student.setName(name); 713 | student.setPassportId(passport); 714 | return student; 715 | } 716 | 717 | @After 718 | public void printAllDataAfterTest() { 719 | System.out.println(service.getAllStudents()); 720 | } 721 | } 722 | ``` 723 | -------------------------------------------------------------------------------- /jdbc-to-spring-jdbc-to-jpa.md: -------------------------------------------------------------------------------- 1 | \mvnw 2 | ``` 3 | #!/bin/sh 4 | # ---------------------------------------------------------------------------- 5 | # Licensed to the Apache Software Foundation (ASF) under one 6 | # or more contributor license agreements. See the NOTICE file 7 | # distributed with this work for additional information 8 | # regarding copyright ownership. The ASF licenses this file 9 | # to you under the Apache License, Version 2.0 (the 10 | # "License"); you may not use this file except in compliance 11 | # with the License. You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, 16 | # software distributed under the License is distributed on an 17 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 | # KIND, either express or implied. See the License for the 19 | # specific language governing permissions and limitations 20 | # under the License. 21 | # ---------------------------------------------------------------------------- 22 | 23 | # ---------------------------------------------------------------------------- 24 | # Maven2 Start Up Batch script 25 | # 26 | # Required ENV vars: 27 | # ------------------ 28 | # JAVA_HOME - location of a JDK home dir 29 | # 30 | # Optional ENV vars 31 | # ----------------- 32 | # M2_HOME - location of maven2's installed home dir 33 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 34 | # e.g. to debug Maven itself, use 35 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 36 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 37 | # ---------------------------------------------------------------------------- 38 | 39 | if [ -z "$MAVEN_SKIP_RC" ] ; then 40 | 41 | if [ -f /etc/mavenrc ] ; then 42 | . /etc/mavenrc 43 | fi 44 | 45 | if [ -f "$HOME/.mavenrc" ] ; then 46 | . "$HOME/.mavenrc" 47 | fi 48 | 49 | fi 50 | 51 | # OS specific support. $var _must_ be set to either true or false. 52 | cygwin=false; 53 | darwin=false; 54 | mingw=false 55 | case "`uname`" in 56 | CYGWIN*) cygwin=true ;; 57 | MINGW*) mingw=true;; 58 | Darwin*) darwin=true 59 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 60 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 61 | if [ -z "$JAVA_HOME" ]; then 62 | if [ -x "/usr/libexec/java_home" ]; then 63 | export JAVA_HOME="`/usr/libexec/java_home`" 64 | else 65 | export JAVA_HOME="/Library/Java/Home" 66 | fi 67 | fi 68 | ;; 69 | esac 70 | 71 | if [ -z "$JAVA_HOME" ] ; then 72 | if [ -r /etc/gentoo-release ] ; then 73 | JAVA_HOME=`java-config --jre-home` 74 | fi 75 | fi 76 | 77 | if [ -z "$M2_HOME" ] ; then 78 | ## resolve links - $0 may be a link to maven's home 79 | PRG="$0" 80 | 81 | # need this for relative symlinks 82 | while [ -h "$PRG" ] ; do 83 | ls=`ls -ld "$PRG"` 84 | link=`expr "$ls" : '.*-> \(.*\)$'` 85 | if expr "$link" : '/.*' > /dev/null; then 86 | PRG="$link" 87 | else 88 | PRG="`dirname "$PRG"`/$link" 89 | fi 90 | done 91 | 92 | saveddir=`pwd` 93 | 94 | M2_HOME=`dirname "$PRG"`/.. 95 | 96 | # make it fully qualified 97 | M2_HOME=`cd "$M2_HOME" && pwd` 98 | 99 | cd "$saveddir" 100 | # echo Using m2 at $M2_HOME 101 | fi 102 | 103 | # For Cygwin, ensure paths are in UNIX format before anything is touched 104 | if $cygwin ; then 105 | [ -n "$M2_HOME" ] && 106 | M2_HOME=`cygpath --unix "$M2_HOME"` 107 | [ -n "$JAVA_HOME" ] && 108 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 109 | [ -n "$CLASSPATH" ] && 110 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 111 | fi 112 | 113 | # For Migwn, ensure paths are in UNIX format before anything is touched 114 | if $mingw ; then 115 | [ -n "$M2_HOME" ] && 116 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 117 | [ -n "$JAVA_HOME" ] && 118 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 119 | # TODO classpath? 120 | fi 121 | 122 | if [ -z "$JAVA_HOME" ]; then 123 | javaExecutable="`which javac`" 124 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 125 | # readlink(1) is not available as standard on Solaris 10. 126 | readLink=`which readlink` 127 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 128 | if $darwin ; then 129 | javaHome="`dirname \"$javaExecutable\"`" 130 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 131 | else 132 | javaExecutable="`readlink -f \"$javaExecutable\"`" 133 | fi 134 | javaHome="`dirname \"$javaExecutable\"`" 135 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 136 | JAVA_HOME="$javaHome" 137 | export JAVA_HOME 138 | fi 139 | fi 140 | fi 141 | 142 | if [ -z "$JAVACMD" ] ; then 143 | if [ -n "$JAVA_HOME" ] ; then 144 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 145 | # IBM's JDK on AIX uses strange locations for the executables 146 | JAVACMD="$JAVA_HOME/jre/sh/java" 147 | else 148 | JAVACMD="$JAVA_HOME/bin/java" 149 | fi 150 | else 151 | JAVACMD="`which java`" 152 | fi 153 | fi 154 | 155 | if [ ! -x "$JAVACMD" ] ; then 156 | echo "Error: JAVA_HOME is not defined correctly." >&2 157 | echo " We cannot execute $JAVACMD" >&2 158 | exit 1 159 | fi 160 | 161 | if [ -z "$JAVA_HOME" ] ; then 162 | echo "Warning: JAVA_HOME environment variable is not set." 163 | fi 164 | 165 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 166 | 167 | # traverses directory structure from process work directory to filesystem root 168 | # first directory with .mvn subdirectory is considered project base directory 169 | find_maven_basedir() { 170 | 171 | if [ -z "$1" ] 172 | then 173 | echo "Path not specified to find_maven_basedir" 174 | return 1 175 | fi 176 | 177 | basedir="$1" 178 | wdir="$1" 179 | while [ "$wdir" != '/' ] ; do 180 | if [ -d "$wdir"/.mvn ] ; then 181 | basedir=$wdir 182 | break 183 | fi 184 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 185 | if [ -d "${wdir}" ]; then 186 | wdir=`cd "$wdir/.."; pwd` 187 | fi 188 | # end of workaround 189 | done 190 | echo "${basedir}" 191 | } 192 | 193 | # concatenates all lines of a file 194 | concat_lines() { 195 | if [ -f "$1" ]; then 196 | echo "$(tr -s '\n' ' ' < "$1")" 197 | fi 198 | } 199 | 200 | BASE_DIR=`find_maven_basedir "$(pwd)"` 201 | if [ -z "$BASE_DIR" ]; then 202 | exit 1; 203 | fi 204 | 205 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 206 | echo $MAVEN_PROJECTBASEDIR 207 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 208 | 209 | # For Cygwin, switch paths to Windows format before running java 210 | if $cygwin; then 211 | [ -n "$M2_HOME" ] && 212 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 213 | [ -n "$JAVA_HOME" ] && 214 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 215 | [ -n "$CLASSPATH" ] && 216 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 217 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 218 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 219 | fi 220 | 221 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 222 | 223 | exec "$JAVACMD" \ 224 | $MAVEN_OPTS \ 225 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 226 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 227 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 228 | ``` 229 | \mvnw.cmd 230 | ``` 231 | @REM ---------------------------------------------------------------------------- 232 | @REM Licensed to the Apache Software Foundation (ASF) under one 233 | @REM or more contributor license agreements. See the NOTICE file 234 | @REM distributed with this work for additional information 235 | @REM regarding copyright ownership. The ASF licenses this file 236 | @REM to you under the Apache License, Version 2.0 (the 237 | @REM "License"); you may not use this file except in compliance 238 | @REM with the License. You may obtain a copy of the License at 239 | @REM 240 | @REM http://www.apache.org/licenses/LICENSE-2.0 241 | @REM 242 | @REM Unless required by applicable law or agreed to in writing, 243 | @REM software distributed under the License is distributed on an 244 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 245 | @REM KIND, either express or implied. See the License for the 246 | @REM specific language governing permissions and limitations 247 | @REM under the License. 248 | @REM ---------------------------------------------------------------------------- 249 | 250 | @REM ---------------------------------------------------------------------------- 251 | @REM Maven2 Start Up Batch script 252 | @REM 253 | @REM Required ENV vars: 254 | @REM JAVA_HOME - location of a JDK home dir 255 | @REM 256 | @REM Optional ENV vars 257 | @REM M2_HOME - location of maven2's installed home dir 258 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 259 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 260 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 261 | @REM e.g. to debug Maven itself, use 262 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 263 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 264 | @REM ---------------------------------------------------------------------------- 265 | 266 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 267 | @echo off 268 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 269 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 270 | 271 | @REM set %HOME% to equivalent of $HOME 272 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 273 | 274 | @REM Execute a user defined script before this one 275 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 276 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 277 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 278 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 279 | :skipRcPre 280 | 281 | @setlocal 282 | 283 | set ERROR_CODE=0 284 | 285 | @REM To isolate internal variables from possible post scripts, we use another setlocal 286 | @setlocal 287 | 288 | @REM ==== START VALIDATION ==== 289 | if not "%JAVA_HOME%" == "" goto OkJHome 290 | 291 | echo. 292 | echo Error: JAVA_HOME not found in your environment. >&2 293 | echo Please set the JAVA_HOME variable in your environment to match the >&2 294 | echo location of your Java installation. >&2 295 | echo. 296 | goto error 297 | 298 | :OkJHome 299 | if exist "%JAVA_HOME%\bin\java.exe" goto init 300 | 301 | echo. 302 | echo Error: JAVA_HOME is set to an invalid directory. >&2 303 | echo JAVA_HOME = "%JAVA_HOME%" >&2 304 | echo Please set the JAVA_HOME variable in your environment to match the >&2 305 | echo location of your Java installation. >&2 306 | echo. 307 | goto error 308 | 309 | @REM ==== END VALIDATION ==== 310 | 311 | :init 312 | 313 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 314 | @REM Fallback to current working directory if not found. 315 | 316 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 317 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 318 | 319 | set EXEC_DIR=%CD% 320 | set WDIR=%EXEC_DIR% 321 | :findBaseDir 322 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 323 | cd .. 324 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 325 | set WDIR=%CD% 326 | goto findBaseDir 327 | 328 | :baseDirFound 329 | set MAVEN_PROJECTBASEDIR=%WDIR% 330 | cd "%EXEC_DIR%" 331 | goto endDetectBaseDir 332 | 333 | :baseDirNotFound 334 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 335 | cd "%EXEC_DIR%" 336 | 337 | :endDetectBaseDir 338 | 339 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 340 | 341 | @setlocal EnableExtensions EnableDelayedExpansion 342 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 343 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 344 | 345 | :endReadAdditionalConfig 346 | 347 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 348 | 349 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 350 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 351 | 352 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 353 | if ERRORLEVEL 1 goto error 354 | goto end 355 | 356 | :error 357 | set ERROR_CODE=1 358 | 359 | :end 360 | @endlocal & set ERROR_CODE=%ERROR_CODE% 361 | 362 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 363 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 364 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 365 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 366 | :skipRcPost 367 | 368 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 369 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 370 | 371 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 372 | 373 | exit /B %ERROR_CODE% 374 | ``` 375 | \pom.xml 376 | ```xml 377 | 378 | 380 | 4.0.0 381 | 382 | com.example 383 | jdbc-demo 384 | 0.0.1-SNAPSHOT 385 | jar 386 | 387 | demo 388 | Demo project for Spring Boot 389 | 390 | 391 | org.springframework.boot 392 | spring-boot-starter-parent 393 | 1.5.3.RELEASE 394 | 395 | 396 | 397 | 398 | UTF-8 399 | UTF-8 400 | 1.8 401 | 402 | 403 | 404 | 405 | org.springframework.boot 406 | spring-boot-starter-jdbc 407 | 408 | 409 | 410 | 411 | com.h2database 412 | h2 413 | 414 | 415 | 416 | org.springframework.boot 417 | spring-boot-starter-web 418 | 419 | 420 | 421 | org.mybatis.spring.boot 422 | mybatis-spring-boot-starter 423 | 1.2.1 424 | 425 | 426 | 427 | org.springframework.boot 428 | spring-boot-starter-data-jpa 429 | 430 | 431 | 432 | org.springframework.boot 433 | spring-boot-starter-test 434 | test 435 | 436 | 437 | 438 | 439 | 440 | 441 | org.springframework.boot 442 | spring-boot-maven-plugin 443 | 444 | 445 | 446 | 447 | 448 | 449 | spring-snapshots 450 | Spring Snapshots 451 | https://repo.spring.io/snapshot 452 | 453 | true 454 | 455 | 456 | 457 | spring-milestones 458 | Spring Milestones 459 | https://repo.spring.io/milestone 460 | 461 | false 462 | 463 | 464 | 465 | 466 | 467 | 468 | spring-snapshots 469 | Spring Snapshots 470 | https://repo.spring.io/snapshot 471 | 472 | true 473 | 474 | 475 | 476 | spring-milestones 477 | Spring Milestones 478 | https://repo.spring.io/milestone 479 | 480 | false 481 | 482 | 483 | 484 | 485 | 486 | 487 | ``` 488 | \src\main\java\com\example\demo\data\student\GenericAllPurposeRepository.java 489 | ```java 490 | package com.example.demo.data.student; 491 | 492 | import javax.persistence.EntityManager; 493 | import javax.persistence.PersistenceContext; 494 | import javax.transaction.Transactional; 495 | 496 | import org.springframework.stereotype.Repository; 497 | 498 | import com.example.demo.entity.Passport; 499 | import com.example.demo.entity.Project; 500 | import com.example.demo.entity.Student; 501 | import com.example.demo.entity.Task; 502 | 503 | @Repository 504 | @Transactional 505 | public class GenericAllPurposeRepository { 506 | 507 | @PersistenceContext 508 | private EntityManager entityManager; 509 | 510 | public Passport getPassport(final long id) { 511 | Passport passport = entityManager 512 | .find(Passport.class, id); 513 | passport.getStudent(); 514 | return passport; 515 | } 516 | 517 | public Task createTask(Task task) { 518 | return entityManager.merge(task); 519 | } 520 | 521 | public Project createProject(Project project) { 522 | return entityManager.merge(project); 523 | } 524 | 525 | public Student createStudent(Student student) { 526 | return entityManager.merge(student); 527 | } 528 | 529 | public void assignStudentToProject(long studentId, long projectId) { 530 | Project project = entityManager.find(Project.class, 531 | projectId); 532 | Student student = entityManager.find(Student.class, 533 | studentId); 534 | project.getStudents().add(student); 535 | } 536 | 537 | } 538 | ``` 539 | \src\main\java\com\example\demo\data\student\StudentRepository.java 540 | ```java 541 | package com.example.demo.data.student; 542 | 543 | import java.util.List; 544 | 545 | import javax.persistence.EntityManager; 546 | import javax.persistence.PersistenceContext; 547 | import javax.persistence.Query; 548 | import javax.transaction.Transactional; 549 | 550 | import org.springframework.stereotype.Repository; 551 | 552 | import com.example.demo.entity.Student; 553 | 554 | @Repository 555 | @Transactional 556 | public class StudentRepository { 557 | 558 | @PersistenceContext 559 | private EntityManager entityManager; 560 | 561 | public Student retrieveStudent(final long id) { 562 | return entityManager.find(Student.class, id); 563 | } 564 | 565 | public Student createStudent(Student student) { 566 | if (student.getPassport() != null) 567 | entityManager.merge(student.getPassport()); 568 | return entityManager.merge(student); 569 | } 570 | 571 | public Student updateStudent(Student student) { 572 | entityManager.merge(student); 573 | return student; 574 | } 575 | 576 | public Student retrieveStudentsFrom(String string) { 577 | return null; 578 | } 579 | 580 | public List retrieveAllStudents() { 581 | Query query = entityManager 582 | .createNamedQuery("find all students"); 583 | return query.getResultList(); 584 | } 585 | } 586 | ``` 587 | \src\main\java\com\example\demo\data\todo\TodoDataService.java 588 | ```java 589 | package com.example.demo.data.todo; 590 | 591 | import java.sql.SQLException; 592 | import java.util.Date; 593 | import java.util.List; 594 | 595 | import com.example.demo.entity.Todo; 596 | 597 | public interface TodoDataService { 598 | 599 | public List retrieveTodos(String user) 600 | throws SQLException; 601 | 602 | public int addTodo(String user, String desc, 603 | Date targetDate, boolean isDone) 604 | throws SQLException; 605 | 606 | public Todo retrieveTodo(int id) throws SQLException; 607 | 608 | public void updateTodo(Todo todo) throws SQLException; 609 | 610 | public void deleteTodo(int id) throws SQLException; 611 | } 612 | ``` 613 | \src\main\java\com\example\demo\data\todo\TodoJdbcService.java 614 | ```java 615 | package com.example.demo.data.todo; 616 | 617 | import java.sql.Connection; 618 | import java.sql.PreparedStatement; 619 | import java.sql.ResultSet; 620 | import java.sql.SQLException; 621 | import java.sql.Statement; 622 | import java.sql.Timestamp; 623 | import java.util.ArrayList; 624 | import java.util.Date; 625 | import java.util.List; 626 | 627 | import javax.sql.DataSource; 628 | 629 | import org.springframework.beans.factory.annotation.Autowired; 630 | import org.springframework.stereotype.Component; 631 | 632 | import com.example.demo.entity.Todo; 633 | 634 | @Component 635 | public class TodoJdbcService implements TodoDataService { 636 | 637 | @Autowired 638 | DataSource datasource; 639 | 640 | // Think about exception handling 641 | // We are explicitly getting the connection! What if there is an 642 | // exception while executing the query! 643 | 644 | @Override 645 | public List retrieveTodos(String user) 646 | throws SQLException { 647 | Connection connection = datasource.getConnection(); 648 | 649 | PreparedStatement st = connection.prepareStatement( 650 | "SELECT * FROM TODO where user=?"); 651 | 652 | st.setString(1, user); 653 | 654 | ResultSet resultSet = st.executeQuery(); 655 | List todos = new ArrayList<>(); 656 | 657 | while (resultSet.next()) { 658 | 659 | Todo todo = new Todo(resultSet.getInt("id"), 660 | resultSet.getString("user"), 661 | resultSet.getString("desc"), 662 | resultSet.getTimestamp("target_date"), 663 | resultSet.getBoolean("is_done")); 664 | todos.add(todo); 665 | } 666 | 667 | st.close(); 668 | 669 | connection.close(); 670 | 671 | return todos; 672 | 673 | } 674 | 675 | @Override 676 | public int addTodo(String user, String desc, 677 | Date targetDate, boolean isDone) 678 | throws SQLException { 679 | Connection connection = datasource.getConnection(); 680 | 681 | PreparedStatement st = connection.prepareStatement( 682 | "INSERT INTO todo(user, desc, target_date, is_done) VALUES (?,?,?,?)", 683 | Statement.RETURN_GENERATED_KEYS); 684 | 685 | st.setString(1, user); 686 | st.setString(2, desc); 687 | st.setTimestamp(3, 688 | new Timestamp(targetDate.getTime())); 689 | st.setBoolean(4, isDone); 690 | 691 | int id = st.executeUpdate(); 692 | 693 | st.close(); 694 | 695 | connection.close(); 696 | 697 | return id; 698 | 699 | } 700 | 701 | @Override 702 | public Todo retrieveTodo(int id) throws SQLException { 703 | Connection connection = datasource.getConnection(); 704 | 705 | PreparedStatement st = connection.prepareStatement( 706 | "SELECT * FROM TODO where id=?"); 707 | 708 | st.setInt(1, id); 709 | 710 | ResultSet resultSet = st.executeQuery(); 711 | 712 | Todo todo = null; 713 | 714 | if (resultSet.next()) { 715 | 716 | todo = new Todo(resultSet.getInt("id"), 717 | resultSet.getString("user"), 718 | resultSet.getString("desc"), 719 | resultSet.getTimestamp("target_date"), 720 | resultSet.getBoolean("is_done")); 721 | 722 | } 723 | 724 | st.close(); 725 | 726 | connection.close(); 727 | 728 | return todo; 729 | 730 | } 731 | 732 | @Override 733 | public void updateTodo(Todo todo) throws SQLException { 734 | Connection connection = datasource.getConnection(); 735 | 736 | PreparedStatement st = connection.prepareStatement( 737 | "Update todo set user=?, desc=?, target_date=?, is_done=? where id=?"); 738 | 739 | st.setString(1, todo.getUser()); 740 | st.setString(2, todo.getDesc()); 741 | st.setTimestamp(3, new Timestamp( 742 | todo.getTargetDate().getTime())); 743 | st.setBoolean(4, todo.isDone()); 744 | st.setInt(5, todo.getId()); 745 | 746 | st.execute(); 747 | 748 | st.close(); 749 | 750 | connection.close(); 751 | 752 | } 753 | 754 | @Override 755 | public void deleteTodo(int id) throws SQLException { 756 | Connection connection = datasource.getConnection(); 757 | 758 | PreparedStatement st = connection.prepareStatement( 759 | "delete from todo where id=?"); 760 | 761 | st.setInt(1, id); 762 | 763 | st.execute(); 764 | 765 | st.close(); 766 | 767 | connection.close(); 768 | 769 | } 770 | 771 | } 772 | ``` 773 | \src\main\java\com\example\demo\data\todo\TodoJPAService.java 774 | ```java 775 | package com.example.demo.data.todo; 776 | 777 | import java.util.Date; 778 | import java.util.List; 779 | 780 | import javax.persistence.EntityManager; 781 | import javax.persistence.PersistenceContext; 782 | import javax.persistence.Query; 783 | import javax.transaction.Transactional; 784 | 785 | import org.springframework.stereotype.Repository; 786 | 787 | import com.example.demo.entity.Todo; 788 | 789 | @Repository 790 | @Transactional 791 | public class TodoJPAService implements TodoDataService { 792 | 793 | @PersistenceContext 794 | private EntityManager entityManager; 795 | 796 | @Override 797 | public List retrieveTodos(String user) { 798 | Query query = entityManager.createNamedQuery( 799 | "find all todos for user", Todo.class); 800 | query.setParameter(1, user); 801 | return query.getResultList(); 802 | 803 | } 804 | 805 | @Override 806 | public int addTodo(String user, String desc, 807 | Date targetDate, boolean isDone) { 808 | Todo todo = entityManager.merge( 809 | new Todo(user, desc, targetDate, isDone)); 810 | return todo.getId(); 811 | } 812 | 813 | @Override 814 | public Todo retrieveTodo(int id) { 815 | return entityManager.find(Todo.class, id); 816 | } 817 | 818 | @Override 819 | public void updateTodo(Todo todo) { 820 | entityManager.merge(todo); 821 | } 822 | 823 | @Override 824 | public void deleteTodo(int id) { 825 | Todo todo = retrieveTodo(id); 826 | entityManager.remove(todo); 827 | } 828 | } 829 | ``` 830 | \src\main\java\com\example\demo\data\todo\TodoMybatisService.java 831 | ```java 832 | package com.example.demo.data.todo; 833 | 834 | import java.sql.SQLException; 835 | import java.util.Date; 836 | import java.util.List; 837 | 838 | import org.apache.ibatis.annotations.Delete; 839 | import org.apache.ibatis.annotations.Insert; 840 | import org.apache.ibatis.annotations.Mapper; 841 | import org.apache.ibatis.annotations.Param; 842 | import org.apache.ibatis.annotations.Select; 843 | import org.apache.ibatis.annotations.Update; 844 | 845 | import com.example.demo.entity.Todo; 846 | 847 | @Mapper 848 | public interface TodoMybatisService 849 | extends TodoDataService { 850 | 851 | @Override 852 | @Insert("INSERT INTO TODO(user, desc, target_date, is_done) VALUES (#{user}, #{desc}, #{targetDate}, #{isDone})") 853 | public int addTodo(@Param("user") String user, 854 | @Param("desc") String desc, 855 | @Param("targetDate") Date targetDate, 856 | @Param("isDone") boolean isDone) 857 | throws SQLException; 858 | 859 | @Override 860 | @Select("SELECT * FROM TODO WHERE id = #{id}") 861 | public Todo retrieveTodo(int id) throws SQLException; 862 | 863 | @Override 864 | @Update("Update todo set user=#{user}, desc=#{desc}, target_date=#{targetDate}, is_done=#{isDone} where id=#{id}") 865 | public void updateTodo(Todo todo) throws SQLException; 866 | 867 | @Override 868 | @Delete("DELETE FROM TODO WHERE id = #{id}") 869 | public void deleteTodo(int id); 870 | 871 | @Override 872 | @Select("SELECT * FROM TODO WHERE user = #{user}") 873 | List retrieveTodos(@Param("user") String user); 874 | 875 | } 876 | ``` 877 | \src\main\java\com\example\demo\data\todo\TodoSpringJdbcService.java 878 | ```java 879 | package com.example.demo.data.todo; 880 | 881 | import java.sql.ResultSet; 882 | import java.sql.SQLException; 883 | import java.sql.Timestamp; 884 | import java.util.Date; 885 | import java.util.HashMap; 886 | import java.util.List; 887 | import java.util.Map; 888 | 889 | import javax.sql.DataSource; 890 | 891 | import org.springframework.beans.factory.annotation.Autowired; 892 | import org.springframework.jdbc.core.JdbcTemplate; 893 | import org.springframework.jdbc.core.RowMapper; 894 | import org.springframework.jdbc.core.simple.SimpleJdbcInsert; 895 | import org.springframework.stereotype.Component; 896 | 897 | import com.example.demo.entity.Todo; 898 | 899 | @Component 900 | public class TodoSpringJdbcService 901 | implements TodoDataService { 902 | 903 | @Autowired 904 | JdbcTemplate jdbcTemplate; 905 | 906 | SimpleJdbcInsert insertTodo; 907 | 908 | @Autowired 909 | public void setDataSource(DataSource dataSource) { 910 | this.insertTodo = new SimpleJdbcInsert(dataSource) 911 | .withTableName("TODO") 912 | .usingGeneratedKeyColumns("id"); 913 | } 914 | 915 | // new BeanPropertyRowMapper(TodoMapper.class) 916 | class TodoMapper implements RowMapper { 917 | @Override 918 | public Todo mapRow(ResultSet rs, int rowNum) 919 | throws SQLException { 920 | Todo todo = new Todo(); 921 | 922 | todo.setId(rs.getInt("id")); 923 | todo.setUser(rs.getString("user")); 924 | todo.setDesc(rs.getString("desc")); 925 | todo.setTargetDate( 926 | rs.getTimestamp("target_date")); 927 | todo.setDone(rs.getBoolean("is_done")); 928 | return todo; 929 | } 930 | } 931 | 932 | @Override 933 | public List retrieveTodos(String user) { 934 | return jdbcTemplate.query( 935 | "SELECT * FROM TODO where user = ?", 936 | new Object[] { user }, new TodoMapper()); 937 | 938 | } 939 | 940 | @Override 941 | public int addTodo(String user, String desc, 942 | Date targetDate, boolean isDone) 943 | throws SQLException { 944 | Map params = new HashMap(); 945 | params.put("user", user); 946 | params.put("desc", desc); 947 | params.put("target_date", targetDate); 948 | params.put("is_done", isDone); 949 | Number id = insertTodo.executeAndReturnKey(params); 950 | 951 | return id.intValue(); 952 | } 953 | 954 | @Override 955 | public Todo retrieveTodo(int id) { 956 | 957 | return jdbcTemplate.queryForObject( 958 | "SELECT * FROM TODO where id=?", 959 | new Object[] { id }, new TodoMapper()); 960 | 961 | } 962 | 963 | @Override 964 | public void updateTodo(Todo todo) { 965 | jdbcTemplate 966 | .update("Update todo set user=?, desc=?, target_date=?, is_done=? where id=?", 967 | todo.getUser(), todo.getDesc(), 968 | new Timestamp(todo.getTargetDate() 969 | .getTime()), 970 | todo.isDone(), todo.getId()); 971 | 972 | } 973 | 974 | @Override 975 | public void deleteTodo(int id) { 976 | jdbcTemplate.update("delete from todo where id=?", 977 | id); 978 | } 979 | 980 | } 981 | ``` 982 | \src\main\java\com\example\demo\DemoApplication.java 983 | ```java 984 | package com.example.demo; 985 | 986 | import org.slf4j.Logger; 987 | import org.slf4j.LoggerFactory; 988 | import org.springframework.beans.factory.annotation.Autowired; 989 | import org.springframework.boot.CommandLineRunner; 990 | import org.springframework.boot.SpringApplication; 991 | import org.springframework.boot.autoconfigure.SpringBootApplication; 992 | 993 | import com.example.demo.data.student.GenericAllPurposeRepository; 994 | import com.example.demo.data.student.StudentRepository; 995 | import com.example.demo.data.todo.TodoDataService; 996 | import com.example.demo.entity.Passport; 997 | import com.example.demo.entity.Project; 998 | import com.example.demo.entity.Student; 999 | import com.example.demo.entity.Task; 1000 | 1001 | //In almost every relationship, independent of source and target sides, one of the two sides will have the join column in its table. That side is called the owning side or the owner of the relationship. The side that does not have the join column is called the non-owning or inverse side. 1002 | //Although we have described the owning side as being determined by the data schema, the object model must indicate the owning side through the use of the relationship mapping annotations. The absence of the mappedBy element in the mapping annotation implies ownership of the relationship, while the presence of the mappedBy element means the entity is on the inverse side of the relationship. The mappedBy element is described in subsequent sections. 1003 | 1004 | @SpringBootApplication 1005 | public class DemoApplication implements CommandLineRunner { 1006 | 1007 | private static final Logger log = LoggerFactory 1008 | .getLogger(DemoApplication.class); 1009 | 1010 | @Autowired 1011 | TodoDataService todoJPAService; 1012 | 1013 | @Autowired 1014 | StudentRepository studentRepository; 1015 | 1016 | @Autowired 1017 | GenericAllPurposeRepository genericRepository; 1018 | 1019 | public static void main(String[] args) { 1020 | SpringApplication.run(DemoApplication.class, args); 1021 | } 1022 | 1023 | @Override 1024 | public void run(String... strings) throws Exception { 1025 | 1026 | runAllStudentExamples(); 1027 | 1028 | /* 1029 | * int todo1 = todoJPAService.addTodo("Ranga", "Dummy10", new Date(), 1030 | * false); 1031 | * 1032 | * int todo2 = todoJPAService.addTodo("Ranga", "Dummy11", new Date(), 1033 | * false); 1034 | * 1035 | * log.info( "Querying for todo records where user = 'Ranga':"); 1036 | * 1037 | * todoJPAService.retrieveTodos("Ranga") .forEach(todo -> 1038 | * log.info(todo.toString())); 1039 | * 1040 | * todoJPAService.updateTodo(new Todo(todo1, "Ranga", "Dummy++", new 1041 | * Date(), false)); 1042 | * 1043 | * log.info("Querying Todo by id " + todo1); 1044 | * 1045 | * log.info(todoJPAService.retrieveTodo(todo1) .toString()); 1046 | * 1047 | * log.info("Deleting todo id " + todo2); 1048 | * 1049 | * todoJPAService.deleteTodo(todo2); 1050 | * 1051 | * log.info( "Querying for todo records where user = 'Ranga':"); 1052 | * 1053 | * todoJPAService.retrieveTodos("Ranga") .forEach(todo -> 1054 | * log.info(todo.toString())); 1055 | * 1056 | */ 1057 | } 1058 | 1059 | private void runAllStudentExamples() { 1060 | Passport passport = new Passport("L12344432", 1061 | "India"); 1062 | 1063 | Student student = createStudent("dummy@dummy.com", 1064 | "Doe", passport); 1065 | student = genericRepository.createStudent(student); 1066 | 1067 | Project project = new Project(); 1068 | project.setName("Project1"); 1069 | 1070 | project = genericRepository.createProject(project); 1071 | 1072 | genericRepository.assignStudentToProject( 1073 | student.getId(), project.getId()); 1074 | 1075 | Task task = new Task(); 1076 | task.setName("Task1"); 1077 | task.setProject(project); 1078 | task.setStudent(student); 1079 | genericRepository.createTask(task); 1080 | 1081 | Student student2 = studentRepository 1082 | .retrieveStudent(101); 1083 | System.out.println("student2 " + student2); 1084 | 1085 | printAllDataAfterTest(); 1086 | 1087 | Passport passport2 = genericRepository 1088 | .getPassport(201); 1089 | System.out.println("passport 2 " + passport2); 1090 | System.out.println("passport 2 Student" 1091 | + passport2.getStudent()); 1092 | } 1093 | 1094 | private Student createStudent(String email, String name, 1095 | Passport passport) { 1096 | Student student = new Student(); 1097 | student.setEmail(email); 1098 | student.setName(name); 1099 | student.setPassportId(passport); 1100 | return student; 1101 | } 1102 | 1103 | public void printAllDataAfterTest() { 1104 | System.out.println( 1105 | studentRepository.retrieveAllStudents()); 1106 | } 1107 | } 1108 | ``` 1109 | \src\main\java\com\example\demo\entity\Address.java 1110 | ```java 1111 | package com.example.demo.entity; 1112 | 1113 | import javax.persistence.Embeddable; 1114 | 1115 | @Embeddable 1116 | public class Address { 1117 | private String street; 1118 | private String city; 1119 | private String state; 1120 | private String zip; 1121 | } 1122 | ``` 1123 | \src\main\java\com\example\demo\entity\Employee.java 1124 | ```java 1125 | package com.example.demo.entity; 1126 | 1127 | import javax.persistence.DiscriminatorColumn; 1128 | import javax.persistence.Entity; 1129 | import javax.persistence.Id; 1130 | import javax.persistence.Inheritance; 1131 | import javax.persistence.InheritanceType; 1132 | 1133 | //@MappedSuperclass 1134 | @Entity 1135 | @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 1136 | @DiscriminatorColumn(name = "disc_type") 1137 | public abstract class Employee { 1138 | @Id 1139 | protected Integer employeeId; 1140 | } 1141 | ``` 1142 | \src\main\java\com\example\demo\entity\FullTimeEmployee.java 1143 | ```java 1144 | package com.example.demo.entity; 1145 | 1146 | import javax.persistence.Entity; 1147 | 1148 | @Entity 1149 | public class FullTimeEmployee extends Employee { 1150 | protected Integer salary; 1151 | } 1152 | ``` 1153 | \src\main\java\com\example\demo\entity\PartTimeEmployee.java 1154 | ```java 1155 | package com.example.demo.entity; 1156 | 1157 | import javax.persistence.Entity; 1158 | 1159 | @Entity 1160 | public class PartTimeEmployee extends Employee { 1161 | protected Float hourlyWage; 1162 | } 1163 | ``` 1164 | \src\main\java\com\example\demo\entity\Passport.java 1165 | ```java 1166 | package com.example.demo.entity; 1167 | 1168 | import javax.persistence.Column; 1169 | import javax.persistence.Entity; 1170 | import javax.persistence.FetchType; 1171 | import javax.persistence.GeneratedValue; 1172 | import javax.persistence.GenerationType; 1173 | import javax.persistence.Id; 1174 | import javax.persistence.OneToOne; 1175 | 1176 | @Entity 1177 | public class Passport { 1178 | 1179 | @Id 1180 | @GeneratedValue(strategy = GenerationType.IDENTITY) 1181 | private long id; 1182 | 1183 | private String number; 1184 | 1185 | @Column(name = "issued_country") 1186 | private String issuedCountry; 1187 | 1188 | // Inverse Relationship 1189 | // bi-directional OneToOne relationship 1190 | // Column will not be created in the table 1191 | // Try removing mappedBy = "passport" => You will see that student_id column 1192 | // will be created in passport 1193 | @OneToOne(fetch = FetchType.LAZY, mappedBy = "passport") 1194 | private Student student; 1195 | 1196 | public Passport() { 1197 | super(); 1198 | } 1199 | 1200 | public Passport(String number, String issuedCountry) { 1201 | super(); 1202 | this.number = number; 1203 | this.issuedCountry = issuedCountry; 1204 | } 1205 | 1206 | public long getId() { 1207 | return id; 1208 | } 1209 | 1210 | public void setId(long id) { 1211 | this.id = id; 1212 | } 1213 | 1214 | public String getNumber() { 1215 | return number; 1216 | } 1217 | 1218 | public void setNumber(String number) { 1219 | this.number = number; 1220 | } 1221 | 1222 | public String getIssuedCountry() { 1223 | return issuedCountry; 1224 | } 1225 | 1226 | public void setIssuedCountry(String issuedCountry) { 1227 | this.issuedCountry = issuedCountry; 1228 | } 1229 | 1230 | public Student getStudent() { 1231 | return student; 1232 | } 1233 | 1234 | public void setStudent(Student student) { 1235 | this.student = student; 1236 | } 1237 | 1238 | @Override 1239 | public String toString() { 1240 | return "Passport [id=" + id + ", number=" + number 1241 | + ", issuedCountry=" + issuedCountry 1242 | + ", student=" + student + "]"; 1243 | } 1244 | 1245 | } 1246 | ``` 1247 | \src\main\java\com\example\demo\entity\Project.java 1248 | ```java 1249 | package com.example.demo.entity; 1250 | 1251 | import java.util.List; 1252 | 1253 | import javax.persistence.Entity; 1254 | import javax.persistence.GeneratedValue; 1255 | import javax.persistence.GenerationType; 1256 | import javax.persistence.Id; 1257 | import javax.persistence.ManyToMany; 1258 | import javax.persistence.OneToMany; 1259 | 1260 | @Entity 1261 | public class Project { 1262 | 1263 | @Id 1264 | @GeneratedValue(strategy = GenerationType.IDENTITY) 1265 | private long id; 1266 | 1267 | private String name; 1268 | 1269 | @OneToMany(mappedBy = "project") 1270 | private List tasks; 1271 | 1272 | // There are some important differences between this many-to-many 1273 | // relationship and the one-to-many relationship discussed earlier. The 1274 | // first is a mathematical inevitability: when a many-to-many relationship 1275 | // is bidirectional, both sides of the relationship are many-to-many 1276 | // mappings. 1277 | // The second difference is that there are no join columns on either side of 1278 | // the relationship. You will see in the next section that the only way to 1279 | // implement a many-to-many relationship is with a separate join table. The 1280 | // consequence of not having any join columns in either of the entity tables 1281 | // is that there is no way to determine which side is the owner of the 1282 | // relationship. Because every bidirectional relationship has to have both 1283 | // an owning side and an inverse side, we must pick one of the two entities 1284 | // to be the owner. In this example, we picked Employee to be owner of the 1285 | // relationship, but we could have just as easily picked Project instead. As 1286 | // in every other bidirectional relationship, the inverse side must use the 1287 | // mappedBy element to identify the owning attribute. 1288 | // Note that no matter which side is designated as the owner, the other side 1289 | // should include the mappedBy element; otherwise, the provider will think 1290 | // that both sides are the owner and that the mappings are separate 1291 | // unidirectional relationships. 1292 | @ManyToMany 1293 | // @JoinTable(name="STUDENT_PROJ", 1294 | // joinColumns=@JoinColumn(name="STUDENT_ID"), 1295 | // inverseJoinColumns=@JoinColumn(name="PROJECT_ID")) 1296 | private List students; 1297 | 1298 | public Project() { 1299 | super(); 1300 | } 1301 | 1302 | public List getTasks() { 1303 | return tasks; 1304 | } 1305 | 1306 | public void setTasks(List tasks) { 1307 | this.tasks = tasks; 1308 | } 1309 | 1310 | public List getStudents() { 1311 | return students; 1312 | } 1313 | 1314 | public void setStudents(List students) { 1315 | this.students = students; 1316 | } 1317 | 1318 | public long getId() { 1319 | return id; 1320 | } 1321 | 1322 | public void setId(long id) { 1323 | this.id = id; 1324 | } 1325 | 1326 | public String getName() { 1327 | return name; 1328 | } 1329 | 1330 | public void setName(String name) { 1331 | this.name = name; 1332 | } 1333 | 1334 | @Override 1335 | public String toString() { 1336 | return "Project [id=" + id + ", name=" + name + "]"; 1337 | } 1338 | 1339 | } 1340 | ``` 1341 | \src\main\java\com\example\demo\entity\Student.java 1342 | ```java 1343 | package com.example.demo.entity; 1344 | 1345 | import java.util.List; 1346 | 1347 | import javax.persistence.CascadeType; 1348 | import javax.persistence.Embedded; 1349 | import javax.persistence.Entity; 1350 | import javax.persistence.GeneratedValue; 1351 | import javax.persistence.GenerationType; 1352 | import javax.persistence.Id; 1353 | import javax.persistence.ManyToMany; 1354 | import javax.persistence.NamedQuery; 1355 | import javax.persistence.OneToMany; 1356 | import javax.persistence.OneToOne; 1357 | import javax.persistence.Table; 1358 | 1359 | @Entity 1360 | @Table(name = "Student") 1361 | @NamedQuery(query = "select s from Student s", name = "find all students") 1362 | // SELECT p.number FROM Employee e JOIN e.phones p WHERE e.department.name = 1363 | // 'NA42' AND p.type = 'Cell' 1364 | 1365 | // Group ing 1366 | // SELECT d, COUNT(e), MAX(e.salary), AVG(e.salary) 1367 | // FROM Department d JOIN d.employees e 1368 | // GROUP BY d 1369 | // HAVING COUNT(e) >= 5 1370 | 1371 | // Query Params 1372 | // SELECT e 1373 | // FROM Employee e 1374 | // WHERE e.department = :dept AND 1375 | // e.salary > :base 1376 | // em.createQuery(QUERY, Long.class).setParameter("deptName", 1377 | // deptName).getSingleResult() 1378 | 1379 | // Read only queries -> 1380 | // @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) 1381 | 1382 | // Criteria criteria = session.createCriteria(Book1.class) 1383 | // .add(Restrictions.eq("name", "Book 1")); 1384 | // List books=criteria.list(); 1385 | 1386 | // Criterion nameRest = Restrictions.eq("name", "Hibernate 1387 | // Recipes").ignoreCase(); 1388 | // gt (greater than), lt (less than), ge (greater than or equal to), isNull, 1389 | // isNotNull, isEmpty, isNotEmpty, between, in, le (less than or equal to) 1390 | // .add(Restrictions.like("name", "%Hibernate%")) 1391 | // .add(Restrictions.between("price", new Integer(100), new Integer(200))); 1392 | // .add(Restrictions.or( 1393 | // Restrictions.like("name", "%Hibernate%"), 1394 | // Restrictions.like("name", "%Java%") 1395 | // ) 1396 | // ) 1397 | 1398 | // Criteria criteria = session.createCriteria(Book.class) 1399 | // .add(Restrictions.like("name", "%Hibernate%")) 1400 | // .createCriteria("publisher") 1401 | // .add(Restrictions.eq("name", "Manning")); 1402 | // List books = criteria.list(); 1403 | // .addOrder(Order.asc("name")) 1404 | // .addOrder(Order.desc("publishDate")); 1405 | 1406 | // .setProjection(Projections.projectionList() 1407 | // .add(Projections.groupProperty("publishDate")) 1408 | // .add(Projections.avg("price"))); 1409 | 1410 | // @MappedSuperclass 1411 | // public class Auditable { 1412 | // @Getter 1413 | // @Setter 1414 | // @Temporal(TemporalType.TIMESTAMP) 1415 | // Date createDate; 1416 | // } 1417 | 1418 | // public class AuditableInterceptor extends EmptyInterceptor { 1419 | // @Override 1420 | // public boolean onSave(Object entity, Serializable id, 1421 | // Object[] state, String[] propertyNames, 1422 | // Type[] types) { 1423 | // if (entity instanceof Auditable) { 1424 | // for(int i=0;i tasks; 1468 | 1469 | @ManyToMany(mappedBy = "students") 1470 | private List projects; 1471 | 1472 | @Embedded 1473 | private Address address; 1474 | 1475 | // @ElementCollection 1476 | // @CollectionTable(name="EMP_PHONE") 1477 | // @MapKeyEnumerated(EnumType.STRING) 1478 | // @MapKeyColumn(name="PHONE_TYPE") 1479 | // @Column(name="PHONE_NUM") 1480 | // private Map phoneNumbers; 1481 | // public enum PhoneType { Home, Mobile, Work } 1482 | 1483 | public List getTasks() { 1484 | return tasks; 1485 | } 1486 | 1487 | public void setTasks(List tasks) { 1488 | this.tasks = tasks; 1489 | } 1490 | 1491 | public void setPassport(Passport passport) { 1492 | this.passport = passport; 1493 | } 1494 | 1495 | public long getId() { 1496 | return id; 1497 | } 1498 | 1499 | public void setId(long id) { 1500 | this.id = id; 1501 | } 1502 | 1503 | public String getName() { 1504 | return name; 1505 | } 1506 | 1507 | public void setName(String name) { 1508 | this.name = name; 1509 | } 1510 | 1511 | public Passport getPassport() { 1512 | return passport; 1513 | } 1514 | 1515 | public void setPassportId(Passport passport) { 1516 | this.passport = passport; 1517 | } 1518 | 1519 | public String getEmail() { 1520 | return email; 1521 | } 1522 | 1523 | public void setEmail(String email) { 1524 | this.email = email; 1525 | } 1526 | 1527 | @Override 1528 | public String toString() { 1529 | return "Student [id=" + id + ", name=" + name 1530 | + ", email=" + email + "]"; 1531 | } 1532 | 1533 | } 1534 | ``` 1535 | \src\main\java\com\example\demo\entity\Task.java 1536 | ```java 1537 | package com.example.demo.entity; 1538 | 1539 | import javax.persistence.Entity; 1540 | import javax.persistence.GeneratedValue; 1541 | import javax.persistence.GenerationType; 1542 | import javax.persistence.Id; 1543 | import javax.persistence.ManyToOne; 1544 | 1545 | @Entity 1546 | public class Task { 1547 | 1548 | public Task() { 1549 | super(); 1550 | } 1551 | 1552 | @Id 1553 | @GeneratedValue(strategy = GenerationType.IDENTITY) 1554 | private long id; 1555 | 1556 | private String name; 1557 | 1558 | @ManyToOne 1559 | // @JoinColumn(name="PROJECT_ID") 1560 | private Project project; 1561 | 1562 | @ManyToOne 1563 | private Student student; 1564 | 1565 | public long getId() { 1566 | return id; 1567 | } 1568 | 1569 | public void setId(long id) { 1570 | this.id = id; 1571 | } 1572 | 1573 | public Project getProject() { 1574 | return project; 1575 | } 1576 | 1577 | public void setProject(Project project) { 1578 | this.project = project; 1579 | } 1580 | 1581 | public Student getStudent() { 1582 | return student; 1583 | } 1584 | 1585 | public void setStudent(Student student) { 1586 | this.student = student; 1587 | } 1588 | 1589 | public String getName() { 1590 | return name; 1591 | } 1592 | 1593 | public void setName(String name) { 1594 | this.name = name; 1595 | } 1596 | 1597 | @Override 1598 | public String toString() { 1599 | return "Task [id=" + id + ", name=" + name + "]"; 1600 | } 1601 | } 1602 | ``` 1603 | \src\main\java\com\example\demo\entity\Todo.java 1604 | ```java 1605 | package com.example.demo.entity; 1606 | 1607 | import java.util.Date; 1608 | 1609 | import javax.persistence.Entity; 1610 | import javax.persistence.GeneratedValue; 1611 | import javax.persistence.GenerationType; 1612 | import javax.persistence.Id; 1613 | import javax.persistence.NamedQuery; 1614 | import javax.persistence.Table; 1615 | 1616 | @Entity 1617 | @Table(name = "Todo") 1618 | @NamedQuery(query = "select t from Todo t where user=?", name = "find all todos for user") 1619 | public class Todo { 1620 | 1621 | @Id 1622 | @GeneratedValue(strategy = GenerationType.IDENTITY) 1623 | private int id; 1624 | 1625 | private String user; 1626 | 1627 | private String desc; 1628 | 1629 | private Date targetDate; 1630 | 1631 | private boolean isDone; 1632 | 1633 | public Todo() { 1634 | super(); 1635 | } 1636 | 1637 | public Todo(int id, String user, String desc, 1638 | Date targetDate, boolean isDone) { 1639 | super(); 1640 | this.id = id; 1641 | this.user = user; 1642 | this.desc = desc; 1643 | this.targetDate = targetDate; 1644 | this.isDone = isDone; 1645 | } 1646 | 1647 | public Todo(String user, String desc, Date targetDate, 1648 | boolean isDone) { 1649 | super(); 1650 | this.user = user; 1651 | this.desc = desc; 1652 | this.targetDate = targetDate; 1653 | this.isDone = isDone; 1654 | } 1655 | 1656 | public int getId() { 1657 | return id; 1658 | } 1659 | 1660 | public void setId(int id) { 1661 | this.id = id; 1662 | } 1663 | 1664 | public String getUser() { 1665 | return user; 1666 | } 1667 | 1668 | public void setUser(String user) { 1669 | this.user = user; 1670 | } 1671 | 1672 | public String getDesc() { 1673 | return desc; 1674 | } 1675 | 1676 | public void setDesc(String desc) { 1677 | this.desc = desc; 1678 | } 1679 | 1680 | public Date getTargetDate() { 1681 | return targetDate; 1682 | } 1683 | 1684 | public void setTargetDate(Date targetDate) { 1685 | this.targetDate = targetDate; 1686 | } 1687 | 1688 | public boolean isDone() { 1689 | return isDone; 1690 | } 1691 | 1692 | public void setDone(boolean isDone) { 1693 | this.isDone = isDone; 1694 | } 1695 | 1696 | @Override 1697 | public int hashCode() { 1698 | final int prime = 31; 1699 | int result = 1; 1700 | result = prime * result + id; 1701 | return result; 1702 | } 1703 | 1704 | @Override 1705 | public boolean equals(Object obj) { 1706 | if (this == obj) 1707 | return true; 1708 | if (obj == null) 1709 | return false; 1710 | if (getClass() != obj.getClass()) 1711 | return false; 1712 | Todo other = (Todo) obj; 1713 | if (id != other.id) 1714 | return false; 1715 | return true; 1716 | } 1717 | 1718 | @Override 1719 | public String toString() { 1720 | return String.format( 1721 | "Todo [id=%s, user=%s, desc=%s, targetDate=%s, isDone=%s]", 1722 | id, user, desc, targetDate, isDone); 1723 | } 1724 | 1725 | } 1726 | ``` 1727 | \src\main\java\com\example\demo\rest\TodoRestService.java 1728 | ```java 1729 | package com.example.demo.rest; 1730 | 1731 | import java.net.URI; 1732 | import java.sql.SQLException; 1733 | import java.util.List; 1734 | 1735 | import org.springframework.beans.factory.annotation.Autowired; 1736 | import org.springframework.http.ResponseEntity; 1737 | import org.springframework.web.bind.annotation.DeleteMapping; 1738 | import org.springframework.web.bind.annotation.GetMapping; 1739 | import org.springframework.web.bind.annotation.PathVariable; 1740 | import org.springframework.web.bind.annotation.PostMapping; 1741 | import org.springframework.web.bind.annotation.PutMapping; 1742 | import org.springframework.web.bind.annotation.RequestBody; 1743 | import org.springframework.web.bind.annotation.RestController; 1744 | import org.springframework.web.servlet.support.ServletUriComponentsBuilder; 1745 | 1746 | import com.example.demo.data.todo.TodoJPAService; 1747 | import com.example.demo.entity.Todo; 1748 | 1749 | @RestController 1750 | public class TodoRestService { 1751 | 1752 | @Autowired 1753 | TodoJPAService todoJPAService; 1754 | 1755 | @GetMapping("/todos/user/{user}") 1756 | public List retrieveTodos( 1757 | @PathVariable String user) throws SQLException { 1758 | return todoJPAService.retrieveTodos(user); 1759 | } 1760 | 1761 | @PostMapping("/todos") 1762 | public ResponseEntity addTodo( 1763 | @RequestBody Todo todo) throws SQLException { 1764 | int todoID = todoJPAService.addTodo(todo.getUser(), 1765 | todo.getDesc(), todo.getTargetDate(), 1766 | todo.isDone()); 1767 | 1768 | URI location = ServletUriComponentsBuilder 1769 | .fromCurrentRequest().path("/{id}") 1770 | .buildAndExpand(todoID).toUri(); 1771 | 1772 | return ResponseEntity.created(location).build(); 1773 | } 1774 | 1775 | @GetMapping("/todos/{id}") 1776 | public Todo retrieveTodo(@PathVariable int id) 1777 | throws SQLException { 1778 | return todoJPAService.retrieveTodo(id); 1779 | } 1780 | 1781 | @PutMapping("/todos") 1782 | public void updateTodo(@RequestBody Todo todo) 1783 | throws SQLException { 1784 | todoJPAService.updateTodo(todo); 1785 | } 1786 | 1787 | @DeleteMapping("/todos/{id}") 1788 | public void deleteTodo(@PathVariable int id) 1789 | throws SQLException { 1790 | todoJPAService.deleteTodo(id); 1791 | } 1792 | } 1793 | ``` 1794 | \src\main\resources\application.properties 1795 | ```properties 1796 | #logging.level.: DEBUG 1797 | spring.h2.console.enabled: true 1798 | 1799 | # Log everything. Good for troubleshooting 1800 | #logging.level.org.hibernate=debug 1801 | #logging.level.org.springframework=debug 1802 | #logging.level.javax.servlet=info 1803 | 1804 | # Log all JDBC parameters 1805 | #logging.level.org.hibernate.type=all 1806 | ``` 1807 | \src\main\resources\data.sql 1808 | ```sql 1809 | INSERT INTO passport(id,number,issued_country) 1810 | VALUES (201,'L1234567','India'); 1811 | INSERT INTO passport(id,number,issued_country) 1812 | VALUES (202,'L1234568','India'); 1813 | 1814 | 1815 | INSERT INTO student(id, name, passport_id, email ) 1816 | VALUES (101,'Jane', 201, 'jane@doe.com'); 1817 | INSERT INTO student(id, name, passport_id, email ) 1818 | VALUES (102,'Doe', 202, 'doe@doe.com'); 1819 | ``` 1820 | \src\main\resources\schema-old.sql 1821 | ``` 1822 | DROP TABLE todo IF EXISTS; 1823 | /* NOT NEEDED WHEN JPA IS ACTIVE 1824 | CREATE TABLE todo( 1825 | id SERIAL auto_increment primary key, 1826 | user VARCHAR(255), 1827 | desc VARCHAR(255), 1828 | target_date TIMESTAMP, 1829 | is_done BOOLEAN); 1830 | */ 1831 | ``` 1832 | \src\test\java\com\example\demo\DemoApplicationTests.java 1833 | ```java 1834 | package com.example.demo; 1835 | 1836 | import org.junit.Test; 1837 | import org.junit.runner.RunWith; 1838 | import org.springframework.boot.test.context.SpringBootTest; 1839 | import org.springframework.test.context.junit4.SpringRunner; 1840 | 1841 | @RunWith(SpringRunner.class) 1842 | @SpringBootTest 1843 | public class DemoApplicationTests { 1844 | 1845 | @Test 1846 | public void contextLoads() { 1847 | } 1848 | 1849 | } 1850 | ``` 1851 | --------------------------------------------------------------------------------