JPA Annotations - How to retrieve all entities with a specific column value - jpa

Let say I have an entity object Customer with an "OneToMany" relation to Order. I want that when ever a "Customer" get loaded, only his orders with the Id = 1234, 5678 get loaded to.
Any ideas?
#Entity
#Table(name = "Customer")
public class Customer extends TraceableJPA {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "customer_id")
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "Customer", targetEntity = Order.class)
#Column(name = "order_id", value = {"1234","5678"} (?))
#OrderBy("isrtdate ASC")
#BatchSize(size = 20)
private List<Order> orders = new ArrayList<Order>();

Hibernate
If you use hibernate Session and its abilites , you can always use #FilterJoinTable mechanism.
Check THIS article for more information.
Yet it is not global, you have to predefine this filter and then explicitly configure Session object to use it.
JPA
JPA in its standard has NO SUCH FUNCTIONALITY, for global relations filtering.
You can always filter it in your queries : )

Related

How can I force Hibernate to use joins to fetch data for instances

I have a Spring Boot application using Hibernate as JPA provider. My application has two entities connected with a #OneToMany / #ManyToOne relation. The relation is annotated with #Fetch(FetchMode.JOIN) on both directions, and fetch = FetchType.EAGER.
My entities are called Car and Driver:
#Entity
#Table(name = "car")
#Data
public class Car implements Serializable, Cloneable {
#Id
#GenericGenerator(name = "car_seq", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", parameters = {
#Parameter(name = "sequence_name", value = "car_seq") })
#GeneratedValue(generator = "car_seq")
private Integer id;
#OneToMany(mappedBy = "car", fetch = FetchType.EAGER)
#Fetch(FetchMode.JOIN)
private List<Driver> drivers = new ArrayList<>();
#Column(name = "license_no", nullable = false)
private String licenseNo;
}
#Entity
#Table(name = "driver")
#Data
public class Driver implements Serializable, Cloneable {
#Id
#GenericGenerator(name = "driver_seq", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", parameters = {
#Parameter(name = "sequence_name", value = "driver_seq") })
#GeneratedValue(generator = "driver_seq")
private Integer id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "car_id", nullable = true)
#Fetch(FetchMode.JOIN)
private Car car;
#Column(name = "name", nullable = false)
private String name;
}
When selecting a care (e.g. by calling Car.findById()), Hibernate joins the the two tables in a single SQL, and returns a Car object with a list of Drivers.
But if I select a single driver, Hibernate will join the Driver and Car table to give me the Driver object with the Car property populated, but it will run a second query to fetch all the driver objects on for the list on the car object.
For performance reasons I would like all the involved objects to be fetched in a single query, as is the case when I fetch a car. But I cannot find a way to make Hibernate do this. There is a property, hibernate.max_fetch_depth, which is supposed to do this, but I have found that it only affects the behavior of fetching a car, not when I fetch a driver.
I know I can use an EntityGraph to control the fetching, and by using an EntityGraph I have successfully retrieved a driver object with its car and all the car's drivers in one query. But to do that, I have to explicitly use a graph when retrieving the object, and I cannot do that in all the various cases where a Car object is needed. There are lots of other entities that have a relation to Car, and I don't want to write an EntityGraph for each and every one of those.
So is there a way to tell Hibernate how you want the fetching to be done by default on an entity? I would have thought that the annotations would be enough, but it seems that there either has to be something more, or that this simply cannot be done.
Arndt
FetchType.EAGER is one of the most common reasons for performance problems. You should use
#OneToMany(mappedBy = "car")
private List<Driver> drivers = new ArrayList<>();
And fetch drivers If needed
SELECT c FROM Car c JOIN FETCH c.drivers

Why my foreign key is null when saving to h2 db, using JPA

What is the difference between these 2 codes. The 1st one shows null on my foreign key which is individualId. The 2nd one is not. Why?
//1st code:
#Entity
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Individual {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "INDIVIDUAL_ID")
private Long individualId;
#OneToMany(mappedBy="individual",cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Identification> identifications = new ArrayList<Identification>();
}
#Entity
public class Identification {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "IDT_ID")
private Long id;
#ManyToOne
#JoinColumn(name="individualId")
private Individual individual;
//second code
//replaced #OneToMany in the first code & then i just dont add #ManyToOne in the Identification Class and it works fine. Why?
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "INDIVIDUAL_ID", referencedColumnName = "INDIVIDUAL_ID")
private List<Identification> identifications = new ArrayList<Identification>();
When i search for JPA tutorial in google the 1st code is the one that i always read. declare #OneToMany in the parent class and add mappedBy, declare #ManyToOne in the child class. But why the 2nd code works perfect than the 1st code? it just let me declare #OneToMany only in the parent class ?
In the class Identification the name of the #JoinColumn does not match any column in your class Individual. It must be the name of the column in the database, which is INDIVIDUAL_ID:
#JoinColumn(name="INDIVIDUAL_ID")

How to write a Spring JPA query for a one to one relationship?

I am new to Spring JPA (or rather looking into it after a long time) and I need some help with writing JPA repository.
I have an entity class Itinerary and User. There is a one to one relationship between the two.
#Entity
#Table(name = "ITINERARY")
public class Itinerary implements Serializable {
#Id
#Column(name = "ID")
#GeneratedValue(generator = "Itinerary_IDGenerator", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "Itinerary_IDGenerator", sequenceName = "Itinerary_IDGenerator", allocationSize = 1)
private long id;
#Basic(optional = false)
#Column(nullable = false)
#Temporal(TemporalType.DATE)
private Date itineraryDate;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USER_ID")
User user;
}
#Entity
#Table(name = "USER")
public class User implements Serializable {
#Id
#Column(name = "ID")
#GeneratedValue(generator = "User_IDGenerator", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "User_IDGenerator", sequenceName = "User_IDGenerator", allocationSize = 1)
private long id;
#Basic(optional = false)
#Column(unique = true, nullable = false)
private String signInName;
}
I want to write a Spring JPA repository for the Itinerary entity to have a method that will return an itinerary for a user (with the specifid singInName) and the itinerary date.
I have write the following interface, but I don't know how to specify the spring query. I have provided a JPA query that works.
public interface ItineraryRepository extends Repository<Itinerary, Long> {
//String queryStr = "select i from Itinerary i where i.user.signInName = '" + signedInUser + "' and i.itineraryDate = :today";
#Query(select i from Itinerary i where i.user.signInName = :signInName and i.itineraryDate = :today)
Itinerary findBySignInNameAndDate(#Param("signInName") String signInName, #Param("itineraryDate") Date itineraryDate);
}
I get an error on the query.
Invalid derived query! No property signInName found for type Itinerary!
and
Syntax error on tokens, delete these tokens
How do I convert this query to a spring query? I could not find an example in the documentation. I am not sure if this is possible at all and whether I am using the repository incorrectly.
Use this method in your repository Interface. And no need of #Query
findByItineraryDateAndUser_SignInName(Date itineraryDate, String signInName);
Spring data is intelligent enough to understand what query it needs to use to fetch results based on your method name(atleast in simple query cases).
User_SignInName specifies to look for a property signInName inside property user.

Feed a list with the last value

I have theses entity and I do this query.
select r from RentAmount r Join r.lodger l join l.bailList b where r.unpaidBalance > 0 and (r.paymentDueDate > :date or r.paymentDueDate is null ) and b.paymentPeriod= order by r.rentAmountId")
Is there a way to feed Lodger.bailList only with the last bail or i would need to loop on every record to get this information?
#Entity
public class RentAmount {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long rentAmountId;
#OneToOne
private Lodger lodger;
}
#Entity
public class Lodger{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long lodgerId;
#OneToOne(fetch = FetchType.LAZY, mappedBy="lodger")
private RentAmount rentAmount;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY, mappedBy = "lodger", orphanRemoval = true)
private List<Bail> bailList;
}
#Entity
public class Bail {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long bailId;
#Enumerated(EnumType.STRING)
private PaymentPeriodEnum paymentPeriod;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "lodger_id")
private Lodger lodger;
}
There are a few options:
One (Non JPA, Hibernate Only)
Ensure the collection is correctly ordered and mark it is as extra lazy. You will have access to the whole collection but accessing of individual items will not trigger a full load.
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/performance.html
"Extra-lazy" collection fetching: individual elements of the
collection are accessed from the database as needed. Hibernate tries
not to fetch the whole collection into memory unless absolutely
needed. It is suitable for large collections.
The mapping will look like:
#OneToMany(mappedBy = "lodger")
#LazyCollection(LazyCollectionOption.EXTRA)
#OrderBy("theRelevantProperty ASC")
private List<Bail> bailList;
public void getCurrentBail(){
//will only load this item from the database
return bailList.get(bailList.size() - 1);
}
Two (Non JPA, Hibernate Only.)
Use the #Where annotation to filter the collection so that while still #OneToMany, only one element will be accessible.
https://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-hibspec-collection
The mapping will look like:
#OneToMany(mappedBy = "lodger")
#Where(clause="some native sql which will filter to include onyl 1item"))
private List<Bail> bailList;
public void getCurrentBail(){
//will be the only item accessible
return bailList.get(0);
}
Three (JPA Compliant)
Would involve creating views at the database level. Various options in this area. If we are only ever interested in the current bail then this view would be similar to option 2 above. Simply point the Bail entity to this view rather than the concrete table:
#Entity
#Table(name = "vw_active_bail")
public class Bail {
}

JPA Query Many To One nullable relationship

I have the following entities and would like to seek help on how to query for selected attributes from both side of the relationship. Here is my model. Assume all tables are properly created in the db. JPA provider I am using is Hibernate.
#Entity
public class Book{
#Id
private long id;
#Column(nullable = false)
private String ISBNCode;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = false)
private Person<Author> author;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = true)
private Person<Borrower> borrower;
}
#Inheritance
#DiscriminatorColumn(name = "personType")
public abstract class Person<T>{
#Id
private long id;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Info information;
}
#Entity
#DiscriminatorValue(PersonType.Author)
public class Author extends Person<Author> {
private long copiesSold;
}
#Entity
#DiscriminatorValue(PersonType.Borrower)
public class Borrower extends Person<Borrower> {
.....
}
#Entity
public class Info {
#Id
private long id;
#Column(nullable=false)
private String firstName;
#Column(nullable=false)
private String lastName;
......;
}
As you can see, the book table has a many to one relation to Person that is not nullable and Person that is nullable.
I have a requirement to show, the following in a tabular format -
ISBNCode - First Name - Last Name - Person Type
How can I write a JPA query that will allow me to select only attributes that I would want. I would want to get the attributes ISBN Code from Book, and then first and last names from the Info object that is related to Person Object that in turn is related to the Book object. I would not want to get all information from Info object, interested only selected information e.g first and last name in this case.
Please note that the relation between the Borrower and Book is marked with optional=true, meaning there may be a book that may not have been yet borrowed by someone (obviously it has an author).
Example to search for books by the author "Marc":
Criteria JPA Standard
CriteriaQuery<Book> criteria = builder.createQuery( Book.class );
Root<Book> personRoot = criteria.from( Book.class );
Predicate predicate = builder.conjunction();
List<Expression<Boolean>> expressions = predicate.getExpressions();
Path<Object> firtsName = personRoot.get("author").get("information").get("firstName");
expressions.add(builder.equal(firtsName, "Marc"));
criteria.where( predicate );
criteria.select(personRoot);
List<Book> books = em.createQuery( criteria ).getResultList();
Criteria JPA Hibernate
List<Book> books = (List<Book>)sess.createCriteria(Book.class).add( Restrictions.eq("author.information.firstName", "Marc") ).list();
We recommend using hibernate criterias for convenience and possibilities.
Regards,