In this example we start with a simple domain model and incrementally migrate it to become more realistic. Along the way we end up using several features of JPA not yet covered by the previous tutorials.
The Problem
title: JPA_Tutorial_3_The_Problem
—
We want to implement a simple system to track books and eventually other resources for a library. This page covers the requirements for Version 1. The problem as stated is bigger than what this tutorial implements. Parts are left as exercises that are scheduled into a course or advanced exercises for students who finish their work early.
Checking out a Book
Description
A Patron checks out one or more books, all of which are due 14 days later.
Basic Course of Events
This use case begins when a Patron identifies him or herself by entering their Patron ID.
The system verifies that the Patron exists and is in good standing.
The system asks the Patron to enter the first resource.
The patron provides the book identifier (each book has a unique identifier because the ISBN is not enough, we need to know WHICH version of Catcher int the Rye the Patron is checking out)
The system records the book, calculates the due date and records the book as on loan to the Patron.
The use case ends.
Alternatives
Num
Step
Description
1
2
The Patron is not in good standing, they have overdue books. Do not allow them to check out any other books until they return all overdue books
2
2
The Patron is not in good standing, they have fines from overdue books they now paid. Do not allow them to check out any books until they pay their fines.
3
2
The Patron is not found (maybe their account was removed due to inactivity). Do not allow the to check out any books
4
5
The Book is not found, log the book and tell the Patron to ask for assistance with the particular book.
5
5
The Book is a reserve book and cannot be checked out. Inform the Patron.
6
5
The due date falls on a day when the Library is not open, move the return date to the next date the library is open.
Returning a Book
Description
A Patron returns a book. The library computes any fines and removes the recording of the loan of the book.
Basic Course of Events
This use case begins when a Patron returns a book. The Patron identifies the book by providing the book identifier.
The system retrieves the loan information for the book.
The system updates the book as being returned and indicates success to the Patron.
The patron indicates they are finished returning books.
The system reports the total of any fines for the books returned as well as any pending fines.
The system asks the user if they would like to pay their fines.
The user indicates the do: Initiate: Paying Fines
The use case ends.
Alternatives
Num
Step
Description
1
2
The book is not on loan, inform the user.
2
3
The book is late, calculate a fine and inform the user of a fine.
3
5
The user owes no fines, the use case ends.
4
6
The user indicates they do not want to pay fines right now. The system informs them they will not be able to checkout books until all fines are paid and the use case ends.
Adding a Book
Description
A Librarian wishes to add a new book into the system.
Basic Course of Events
The Librarian indicates they want to add a new Book.
The system asks the Librarian to provide book information (Book Title, Authors, ISBN, replacement cost)
The Librarian provides the book information.
The system validates the information.
The system creates a new book and assigns the book a unique identifier.
The system indicates the unique identifier for the book (and prints a book label)
The use case ends.
Alternatives
No alternatives listed for this use case.
Removing a Book
Description
The Librarian wishes to take a book out of the system and make it no longer available for checkout.
Basic Course of Events
The Librarian indicates they want to remove a book.
The system asks the librarian for the book identifier.
The Librarian provides the book identifier.
The system validates the book identifier and book.
The system removes the book from the system and indicates success.
Alternatives
Num
Step
Description
1
3
The book identifier is not found. Indicate the error. The use case ends.
2
4
The book is on loan. Remove the loan (ignoring any fines). Indicate the error to the user but complete the use case normally.
3
4
This is the last book with the that particular ISBN. Ask the user to confirm the removal. If confirmed, complete the use case normally. If not confirmed, do not remove the book. Either way, the use case ends.
Adding a Patron
Description
A Librarian adds a new Patron into the system.
Basic Course of Events
The Librarian indicates they wish to add a new Patron to the system.
The system asks the Librarian to provide the Name (first, mi, last), Address (street 1, street 2, city, state, zip), and Phone number(area code + 7 digits).
The system verifies the minimal information is provided.
The system creates a new Patron and assigned a Patron ID.
The system provides the new Patron ID back to the Librarian (and prints a card).
The use case ends.
Alternatives
Num
Step
Description
1
3
Some required information is missing. Indicate the required information and ask the Librarian to perform it. Continue back at step 2.
Removing a Patron
Description
The Librarian wants to remove a Patron.
Basic Course of Events
The Librarian indicates they want to remove a Patron.
The system asks for the Patron’s id.
The Librarian provides the id.
The system validates the id.
The system removes the Patron from the system.
Alternatives
Num
Step
Description
1
3
The id is not found. Indicate the error to the user and continue at step 2
2
3
The Patron has outstanding fines. Indicate this to the Librarian and ask to confirm the removal. If confirmed, remove and complete the use case normally. If not confirmed, end the use case without removing the Patron.
3
3
The Patron has outstanding loans. Indicate this to the Librarian and do not allow removal.
Paying Fines
Description
A Patron wishes to pay fines. Note that this use case can be invoked by itself or called from other use cases.
Basic Course of Events
A Patron is identified and their fines calculated.
The system asks for the amount tendered.
The system determines the difference and indicates the difference to the user.
The use case ends.
Alternatives
Num
Step
Description
1
1
The identified Patron has no fines. Indicate this to the user and the use case ends.
2
4
If there is still a balance, the system asks if it should ask for additional reimbursements. If yes, they go back to step 2, otherwise the use case ends.
Record a Book as Unrecoverable
Description
A book is not going to be returned/recovered. Add a fine if the book is on loan.
Basic Course of Events
This use case begins when a book is going to indicated as not returnable.
The system asks the user to provide the book id and a reason.
The user provides the id and reason.
The system retrieves the book.
The system calculates the replacement cost assigns it to the Patron who has it checked out.
The book is removed from the system.
Alternatives
Num
Step
Description
1
3
The book id is not known. Retrieve a list of books checked out to a Patron, select from the list and continue to step 3.
2
3
The book id is not known. Provide the isbn. Select the user who has the book checked out and select the book by id. Continue at step 3.
3
3
The book id is not known. Provide the title. Select the user who has the book checked out and select the book by id. Continue at step 3.
4
5
The book is not checked out, do not calculate any fines.
Reviewing all Checkouts for a Patron
Description
Report all of the books currently checked out by a Patron. Provide the title, isbn and due date. Sort by due date, with the book due the soonest at the beginning. If the user has an outstanding balance, indicate that as well.
Reviewing all Fines for all Patrons
Present a list of all the patrons with fines. Sort by the last name followed by the first name. Provide the name of the user, their phone number and their total balance.
V1 Project Setup
title: JPA_Tutorial_3_Project_Setup
—
For the rest of this section, when you see ****, replace it with **JpaTutorial3**
title: JPA_Tutorial_Project_Setup
—
Create Java Project
Next we need to create a Java project. We’ll keep the source separate from the bin directory:
Pull down the File menu and select New:Project
Select Java Project and click on Next
Enter a project name: ****, again read [this](JPA_Tutorial_1_Getting_Started#SideBarJpaClassPath) to know why I did not use a space in the project name.
Make sure “Create new project in workspace” is selected.
Make sure the JRE selected is 1.5.x or higher. If such a JRE does not show in the list, you can add it through Window->Preferences->JAVA->Installed JRE’s.
Select Create separate source and output folders
Click Finish
Create folders and packages
Expand your **** folder
Select the src directory
Right-click, select new:Folder
Use the name META-INF
Make sure **** is still selected, right-click and select **New:Source Folder**
Enter test and click OK
Add Required Libraries
We now need to add two libraries. Note that these steps assume you’ve already worked through the first tutorial and are working in the same workspace. If you, you’ll need to create user libraries. Review Creating User Libraries.
Edit the project properties. Select your **** and either press **alt-enter** or right-click and select properties.
Select Java Build Path
Click on the Libraries tab
Click on Add Library
Select User Libraries and click Next
Select JPA_JSE by click on the check box
Click OK
Click on Add Library again
Click on JUnit
Click Next
In the pull-down list, select JUnit 4
Click Finish
Click OK
If you’d like some background information on JUnit, please go here.
Configure Persistence Unit
<hr />
<p>title: JpaPersistenceUnit —</p>
<p id="Persistence_xml">We now need to create the Persistent Unit definition. We are going to create a file called persistence.xml in the src/META-INF directory with the following contents:</p>
<h3 id="persistencexml">persistence.xml</h3>
<figure class="highlight">
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><pre><code class="language-xml" data-lang="xml"><span class="nt">&lt;persistence&gt;</span> <span class="nt">&lt;persistence-unit</span> <span class="na">name=</span><span class="s">"examplePersistenceUnit"</span>
<span class="na">transaction-type=</span><span class="s">"RESOURCE_LOCAL"</span><span class="nt">&gt;</span>
<span class="nt">&lt;properties&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">"hibernate.show_sql"</span> <span class="na">value=</span><span class="s">"false"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">"hibernate.format_sql"</span> <span class="na">value=</span><span class="s">"false"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">"hibernate.connection.driver_class"</span>
<span class="na">value=</span><span class="s">"org.hsqldb.jdbcDriver"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">"hibernate.connection.url"</span>
<span class="na">value=</span><span class="s">"jdbc:hsqldb:mem:mem:aname"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">"hibernate.connection.username"</span> <span class="na">value=</span><span class="s">"sa"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">"hibernate.dialect"</span>
<span class="na">value=</span><span class="s">"org.hibernate.dialect.HSQLDialect"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">"hibernate.hbm2ddl.auto"</span> <span class="na">value=</span><span class="s">"create"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/properties&gt;</span> <span class="nt">&lt;/persistence-unit&gt;</span> <span class="nt">&lt;/persistence&gt;</span></code></pre> </code></pre></div> </div>
</figure>
<h3 id="the-steps">The Steps</h3>
<ul>
Expand your ****</li>
Select the src directory</li>
Find the src/META-INF directory (if one does not exist, right-click, select New:Folder, enter META-INF and press enter)</li>
Right click the src/META-INF, select new:File.</li>
Enter persistence.xml for the name and press “OK” (Note: all lowercase. It won’t make a difference on Windows XP but it will on Unix.)</li>
Copy the contents (above) into the file and save it</li>
</ul>
</div>
</div>
Update persistence.xml
Update Persistence Unit Name
The name of the persistence unit in your just-copied persistence.xml is examplePersistenceUnit in this example we use lis for Library Information System. Make the following change:
Before we get started, this tutorial is deliberately organized in an inconvenient fashion. Why? My target reader is someone in a class I’m teaching (the material is open-source but still targeted). I do not want the student to be able to quickly just copy the whole thing and get it to work without having to put forth some effort. In a classroom situation, I have all of the source code available if I need to help a student get up to speed.
We’ll start with a stripped down version of the requirements. This first test suite handles the following test cases:
Create a Patron
Remove a Patron
Update a Patron
Attempt to find Patron that does not exist.
Notice that this suite of tests is for Creating, Reading, Updating and Deleting (CRUD) Patrons.
Assuming you’ve done Tutorial 2, much of the boilerplate code is going to look the same. First let’s write a unit test for each of these test cases:
Create a Patron
This test first creates a patron using a private utility method. This method exists because it is used later in other unit tests.
Looking at the test, it uses an attribute called dao. This is a Data Access Object (which we’ll later convert to a stateless Session Bean). This Data Access Object will be responsible for retrieving, creating and removing Patrons.
Remove a Patron
This test uses the utility method to create a patron. It then removes it and makes sure that when we try to retrieve it that the Patron no longer exists.
Update a Patron
We create a patron then update it.
Attempt to find Patron that does not exist
Verify that when we try to find a patron that’s not found, we get back null.
Supporting Code
We have several veterans returning from previous tutorials. And here they are:
PatronDaoTest
First the imports and the attributes. Note that this is a complete class that will compile. It just doesn’t do anything yet.
Initialization of the Logger
This is our 1-time initialization of the logging system.
Getting EMF and EM
Now before each unit test we’ll look up the entity manager factory, create a dao, create an entity manager and pass it into a DAO and finally start a transaction.
Clean up after each test
After each test we’ll rollback the transaction we created in the pre-test initialization. We’ll then close both the entity manager and entity manager factory. This keeps our tests isolated.
The Entities
We need to create entities. These entities are a bit more well-specified that what you’ve seen in the previous tutorials. In most cases I believe the extra information is intuitive. Where it is not, I’ll try to point out what is going on.
Address.java
Patron.java
Finally, the Data Access Object
The DAO has the following four methods:
createPatron
retrieve
removePatron
update
We’ll look at each of these, although none of this will be new if you’ve looked at the first tutorial.
createPatron
Given the information to create a patron, instantiate one and then persiste it. Note that this is written in a style that will natually fit into a Session Bean.
retrieve
This uses the find method built into the entity manager. It returns null if not found. It first sees if the object is in the first-level cache. If not, it retrieves it from the database.
removePatron
To remove an object we have to find it first. You do not provide a class and a key. So we first retrieve it (it might already be in the cache so this may not involve a database hit. We then issue the remove of the object.
update
Update uses the merge method to get its work done. Note that it returns what is returned from merge. Why? The provided patron could be detached (retrieve during another transaction or from a different instance of an entity manager. If this is the case, then the object will not be put into the cache (and therefore become managed). Instead, a new instance is created and the contents of the paramter is copied into the new, managed instance. That new managed instance is returned. If the provided patron is managed, then there’s actually not need to even call this method because any changes made to the patron will be reflected in the patron after the transaction is closed.
The rest of the class
Here are the imports, attributes and getters/setters.
V1 Second Test Suite
title: JPA_Tutorial_3_V1_Second_Test_Suite
—
We started with Patron. In round 2, we add the basic support for the Book. The book dao needs the same basic tests:
Creating a Book
Removing a Book
Updating a Bookadd
Note that we did not also include retrieving a book. We use this functionality in all of the tests anyway so I do not include a specific test for that functionality. This might seem like we’re not isolating tests perfectly but then I’ve never seen or come up with a “perfect” solution to this issue and this seems adequate to me.
We’ve already written a test very much like the above list if you consider PatronTest. We can extract quite a bit of common code out of our PatronTest and reuse it in our BookTest class. Take a look at this base class (note the embedded comments contain background information):
BaseDbDaoTest.java
Now let’s see how this impacts the creation of our new BookTest class. We’ll start with everything but the tests and then look at each test.
Everything but the Tests
Here is the test class minus all of the tests.
Creating a Book
We wrote this pretty much the same as in the Patron test. It might seem like we could get further reuse between tests and we could but at the cost of probably a bit too much indirection.
Removing a Book
This test method looks just like one in the PatronTest class. If you’re looking for an advanced exercise, consider moving all of the tests in the base class and making the derived class methods use them somehow. Warning, you might want to look up annotation inheritance.
Updating a Book
Try to find a non- existant book
Note that with the introduction of the base class we’ll also need to make changes to PatronTest. Here’s the updated version of PatronTest taking the new base class into consideration.
PatronDaoTest.java Updated
The Dao Classes
The BookDao looks a whole lot like the PatronDao:
BookDao.java
Note that this class depends on a simple base class, the BaseDao, which offers support for storing the Entity Manager attribute:
BaseDao.java
And finally, here’s the updated PatronDao that has been rewritten to use the BaseDao.
PatronDao.java
The Entity Model
We’ve added support for a Book and along the way we had to add in a few more classes. After the second test suite, we’re up to the following entities:
Entity
Description
Address
This entity represents the address for both an Author and a Patron. In the first tutorial we embedded this class. Now we’re allowing it to exist in its own table as a first-class citizen rather than embedding it.
Author
Books and Authors have a bi-directional, many to many relationship with each other. That is, a book has one to many Authors and an Author has one to many books. This entity represents one author and maintains a Set representing each of its books. We treat the Author as the secondary part of the relationship and the book as Primary.
Book
The book is a key entity in our system. It maintains a set of Authors and is considered the master of the bi-directional relationship. In version 1 of our system, the relationship between Books and Patrons is direct. We’ll change that in version 2.
Name
Authors and Patrons both have a name. Rather than duplicate the definition of names in both classes, we create a Name entity. This entity is embeddable, meaning its attributes will be stored as columns in the entities in which it is contained rather than as rows in a table all of its own.
Patron
The patron borrows books, so it has a Set as well as an embedded Name.
Now let’s review the code for each of these entities. As with previous examples, pay attention to the embedded comments.
Address
Author
Book
Name
Patron
V1 Third Test Suite
title: JPA_Tutorial_3_V1_Third_Test_Suite
—
Typical enterprise systems are build on a multi-tiered system. There are usually at least three tiers:
Presentation
Business
Integration
There might be a few more, but for now this list of tiers will suite us well.
Our first two tests produced Data Access Objects (dao)’s. These two dao’s hide the details of getting books and patrons. They fall under the integration layer.
Now it is time to add a higher-level concept, the Library. The Library class represents a Facade to the underlying system. This so-called facade will be the primary interface to the middle tier of our system.
Of course, along the way we’ll end up doing yet more refactoring to accommodate this new suite of tests.
Library
First we’ll start with a new suite of tests for this Library facade. For this first pass, we’ll write several basic tests and a few tests that move us closer to use-case like functionality.
Adding a Book
Lookup a Book that Does Not Exist
Notice that this test has different results than the same test in the BookDaoTest. In this case we expect an exception to be thrown while in the case of the BookDaoTest we just get back null. Why? The dao has no way of knowing what the policy should be regarding not finding objects, whereas the Library facade can set the policy.
Adding a Patron
Lookup a Patron that Does Not Exist
As with the BookDao, the PatronDao simply returns null if an object is not found by ID. The Library changes that null result into an exception.
Checking out a book to a patron
Returning a book
Returning a book that is not checked out
Checking out a Book that is Already Checked Out
Checkout a Book that Does Not Exist
Checkout a Book to a Patron that Does Not Exist
LibraryTest.java
Here’s the shell of the test.
EntityManagerBasedTest
This new class inherits from a new base class called EnttyManagerBasedTest. This class factors out just the part of initialization related to the entity manager and the transactions from the BaseDbDaoTest.
BaseDbDaoTest
Here is yet another updated BaseDbDaoTest that reflects the new base class.
The Exception
We’ve added one new unchecked exception to our system, BookAlreadyCheckedOut. Here it is:
Library
This class is all new.
BookDao
The tests use the findByIsbn() method, which returns a collection of Books. Why does findByIsbn() return a collection of books? The isbn is not unique; the book id is the only unique column. If we enforced a unique isbn, then there could only be one book of a given isbn in the library.
We’ve also added a method, findById, which should return a unique value (or null).
Util
We need a basic utility to assist with equality. This utility will handle when we have null references.
EqualsUtil
EqualsUtilTest
Entity Changes
Book
The book is somewhat changed. First it needs to import util.EqualsUtil (as shown below). It also contains some named queries and three new methods: isOnLoanTo, isOnLoan and checkin. The code below shows these changes.
Patron
There was only one change to Patron. We want to be able to ask the Patron if it is in fact borrowing a particular book.
V1 Assignments
title: JPA_Tutorial_3_V1_Assignments
—
Questions
Given our current solution, how would you add support for:
Return dates
Fines
Review how we return a book. Does it seem strange that we retrieve the book, get the patron, update both of them and then merge the patron?
How are the first two questions related?
Advanced: If you have spare time
Write a simple user interface. Your interface should support the following operations:
Add a book
Add a patron
Checkout a book to a patron
Return a book
Your choice on the type of user interface, text, servlet, swing, …
V2 Requirements: Relational Table
title: JPA_Tutorial_3_V2_Requirements
—
In the first version of our simple system, we had a 1 to many relationship from Patron to Book and a many to 1 relationship from Book to Patron. On a UML diagram, this looks like the following (only showing this one relationship):
In reality, this relationship might better be described as:
If you take the UML interpretation of this diagram, it says that when a Patron and Book come together, there are attributes associated withe the relationship between them.
We could simply put a few dates on the book, checkoutDate and dueDate. The problem is that when the book is checked out we have three non-null attributes: checkoutDate, dueDate, borrowedBy, and when the book is not checked out, those same three attributes are null. This seems a bit awkward.
So we are going to update our example to provide support for tracking the date a book was checked out and the date it is due. We will also calculate fines and move a bit closer to being able to fully support the use case to checkout books.
V2 Updated Library Test Suite
title: JPA_Tutorial_3_V2_First_Test_Suite
—
In this second version, we add the following features:
We track when a book was checked out and when it is due
We calculate fines when returning books
We associate fines with patrons
We allow the patron to pay for their fines
We disallow patrons from checking out books when they have fines
Along the way, we make a lot of additions and changes. Based on the updated LibraryTest, here is a list of all the changes I made to get things to work (note if you choose to start from the test and make things work yourself, you results may vary):
src/entity
Book
Now has an optional Loan object instead of a direct reference to a Patron.
Fine
New class, represents an individual fine generated from returning one book late. A Patron has zero to many of these.
Loan
New class, represents the information related to the relationship between Patron and Book. A Patron has a One to Many relationship with Loan while a book as a One to One that is optional (can be null).
LoanId
A key-class for the Loan class. The key is two columns, a foreign key to Patron and a foreign key to Book.
Patron
Now has a One to Many relationship with both Loan and Fines. It also has several new methods in support of those new/changed attributes.
src/exception
BookNotCheckedOut
New exception class. Thrown when trying to return a book that is not checked out.
InsufficientFunds
New exception class. Thrown when Patron tries to pay fines but does not tender enough cash.
PatronHasFines
New exception class. Thrown when Patron tries to check out a book but already has fines.
src/session
Library
Substantially changed in support of the new requirements.
LoanDao
New class. Provides some simple query support directly related to loan class.
src/util
DateTimeUtil
A new class. Provides some basic date/time utilities.
test/session
LibraryTest
Several new tests in support of new functionality.
test/util
DateTimeUtilTest
Several test in support of new utility class.
New Utility
To calculate fines, we needed to determine the number of days late a Patron returned a Book. Here are the tests for that class:
DateTimeUtilTest.java
DateTimeUtil
The Exceptions
Here are the three new exception classes:
BookNotCheckedOut
InsufficientFunds.java
PatronHasFines.java
The Library Test
Many of the original tests are different from the previous version. Additionally, there are many new tests. Here is the test. Once you get this in to your system, you might want to simply get all of the tests methods to compile and then get the tests to pass.
Doing so is approaching formal TDD. It is different in a few important respects:
You are given the tests rather than writing them yourself
You are working on many tests at once rather than just one (or a very few) at a time
Even so, this suite of test fully express the new set of requirements for version 2.
V2 Updated Sessions
title: JPA_Tutorial_3_V2_Updated_Sessions
—
We’ve added a new session, LoanDao. It essentially provides a few queries dealing with loans such as finding all overdue books or finding all patrons with overdue books.
LoanDao.java
Library.java
V2 Updated Entities
title: JPA_Tutorial_3_V2_Updated_Entities
—
The biggest change this version was the addition of a Loan entity. A loan represents information about the relationship between Book and Patron. It specifically stores the checkout date and the due date. The Loan entity represents a so-called join table in the database. There are ways to specify a join table without creating an Entity, however we created the entity because we wanted to store additional information about the relationship. It also, arguably, makes some of our queries easier having Loan as an entity rather that just described as a join table.
Loan.java
LoanId.java
Book.java
Fine.java
Patron.java
V2 Assignments
title: JPA_Tutorial_3_V2_Assignments
—
Patrons with Overdue Books
A Patron cannot checkout a book if they have any outstanding fines. Can they checkout a book if they have overdue books?
Write a test to determine if they can or cannot. If they can, update the system somehow to make it impossible to checkout books if the Patron has overdue books.
Paying Fines
Right now, a Patron can only pay fines if they tender at least as much as their total fines. Allow a Patron to pay partial fines. Paying from the oldest to the newest fine, remove as many complete fines. Once they no longer have enough money to pay a fine fully, calculate the balance due and leave all the remaining fines associated with a Patron.
Write the following tests to support your new functionality:
Pay all of a Patron’s fines in 2 steps with exact change.
Pay all of a Patron’s fines in 2 steps with more than the required amount.
Pay part of a Patron’s fines and then verify that they still cannot checkout books. Then pay the rest of the fines and verify that they can checkout books.
Updated UI/Add a UI
Consider adding a user interface (or updating the one you’ve already created). Support the new functionality of paying fines, listing fines, listing overdue books, listing patrons with overdue books, etc.
Your user interface will need to handle the exceptions that might be thrown by the system (or you could just make sure to not do anything wrong).
Advanced: Inheritance
What happens if you create a new kind of resource, say a DVD. Now a patron can checkout a book or a DVD. Provide support for this functionality.
Note: this will take some time and we’ll be looking at this kind of functionality later, so only attempt this assignment if you have a good amount of time.
FAQ
title: JPA_Tutorial_3_FAQ
—
JPA Tutorial 3 - FAQ
Phone number length is set to 11 in the annotation in the exercise, but phone numbers are 12. What’s happening?It will get truncated (in hypersonic)//
TDD: Is there a tool (eclipse plugin) to generate a concrete class based on a test case?Use Quick-fix (Ctrl-1 or click the icon on the sidebar) to create the class, and stub methods.//
When do Named Queries get compiled?When you create the EntityManager factory.//
Is there something that can use to see the db structure based on the mappings?After the entitymanager creates the db, use something like DB Visualizer//
What did we learn/observe so far (mid-day)?
varargs for methods
cascading types - persist, all, refresh. propagates operations (merge/update/persist/refresh) across entities. Saves you from having to persist things.
jpa requires jdk 1.5
the @column annotation sets the name of the column in the database. also lets you specify things like width/length (attribute of the annotation).
debugging good
eclipse can gen hashcode/equals
What did we learn/observe so far (end of day)?
Brett: Why we use a DAO .
Brett: Contrast the Library to the DAO’s .
? When you get your objects, they’re fully configured (nice). Brett: makes it more testable
? Defines attributes for a particular field in DB. Brett: affects physical characteristics as opposed to logical.
? saves lines of code
? brett: hide a warning based on actual query parameter type (not available at compile-time)
? You can have only one version of the annotation on a given object
? confusing, brett: heavy-handed/overkill
? helps if you decide you want to change how you’re accessing your database.
? have to look at code to understand what’s changing (head nods)
) gives compiler ability to flag problem. some class discussion of when needed, when not…
l Brett:time/datastamp
//What else have you learned today?//
e
)
.
? defines the sort order
//Day 3 - Tutorial #3
Questions//
Patron has a one-to-many for fines, but no many-to-one on the fines side. Why? Just an example of a uni-directional relationship.
Why is insertable false? (in exercise) We think: So that loan has to point at things which already exist. (as opposed to creating new loan/patron at same time)
? Hold off on that because the next few exercises build up additional requirements which may change your mind
//What else have you learned today?//
//How we can create/persist a given entity//
s
//Query syntax is better/easier//
//Notes for Brett://
.
s
A Patron can return a book while having an overdue book
Below are the tests to check everything:
And the new feature that doesn’t allow to checkout with overdue books.
These tests are in LibraryTest.java
And here are the changes in project:
There is a new exception class called: PatronHasOverdueBooks
Here it is:
In Library class, I added to the checkout method a validation for overdue books:
Also, in Library class, the new method: getNumberOfOverdueBooksOfPatron
LoanDao can return the number of overdue books of specific Patron:
It uses a new named-query. One of the parameter is the Patron (not the patron’s id). I wanted to see how the join works …
Comments