Get last record from #OneToMany relationship - jpa

I have a couple of entities with a #ManyToOne and #OneToMany relationships, and the thing is that I am looking for a way to get the last record inserted from the #OneToMany side of the relationship without loading all the records from the list, Actually, I am saving this last record in a #OneToOne relationship in ClassB, but that creates too many conflicts with FK constraints. Here is an extract of how it looks like:
public class ClassA {
#Id
public Long id;
#ManyToOne
public ClassB classB;
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
public Date startDate;
}
public class ClassB {
#Id
public Long id;
#OneToMany(mappedby = "classB", fetch = FetchType.LAZY)
public List<ClassA> classAList = new ArrayList<>();
#OneToOne
public ClassA lastClassA; // Generates a bidirectional FK, and unable the entity for deletion.
}
The interaction between these classes is that ClassA is accumulated over time and is saved linked to ClassB, at the time of ClassB do some work, it only needs the last ClassA instance created (which would be the current ClassA), the previous instances of ClassA are not important since they are in the past now, and are only kept for history. So, because of this I created the field lastClassA which is updated every time a new ClassA is created and saved on disk.
I could also create a JPQL to get this last Record from the classAList field (demo bellow), but I am not sure that is the best way to do it. So, does anybody know about a strategy to get this last record without loading the entire list and selecting the last member of the list?
Select a from ClassA a where a.startDate = (Select MAX(b.startDate) from ClassA b where ClassB.id=:classBId)

Related

JPA Criteria API join on 3 tables and some null elements

I have one parent entity that has two child entities as attributes.
I want to select all elements from the parent entity that have EITHER a childOne with a given parameter as personal attribute OR childTwo with that same given parameter as personal attribute.
Here are my three classes simplified:
The Parent Object:
#Entity
public class ParentObject {
#Id
private int id;
private int fkChildOne;
private int fkChildTwo;
#ManyToOne
#JoinColumn(name = "fk_child_one_id", referencedColumnName =
"child_one_id")
private ChildOne childOne;
#ManyToOne
#JoinColumn(name = "fk_child_one_id", referencedColumnName =
"child_one_id")
private ChildTwo childTwo;
// getters and setters
}
The Child One Object:
#Entity
public class ChildOne {
#Id
private int childOneId;
private String nameChildOne;
#OneToMany
#JoinColumn(name = "fk_child_one_id")
private List<ParentObject> parents;
// getters and setters
}
The Child Two Object:
#Entity
public class ChildTwo {
#Id
private int childOneId;
private String nameChildTwo;
#OneToMany
#JoinColumn(name = "fk_child_two_id")
private List<ParentObject> parents;
// getters and setters
}
The Specs Class:
public static Specification<ParentObject> checkName(String name) {
return Specifications.where(
(root, query, builder) -> {
final Join<ParentObject, ChildOne> joinchildOne =
root.join("childOne");
final Join<ParentObject, ChildTwo > joinchildTwo =
root.join("childTwo");
return builder.or(
builder.equal(joinchildOne .get("nameChildOne"), name),
builder.equal(joinchildTwo .get("nameChildTwo"), name)
);
}
);
}
When this spec is called in my service, I get no results. However, if I comment out one of the two joins and the corresponding Predicate in my builder.or method, then I get some results but they obviously don't match what I'm looking for, which is to select every ParentObject that have either ChildOne with that parameter or ChildTwo with that paramater.
Any clue what's wrong with the code ?
Finally got the solution : to fetch all the corresponding results, I had to add the type of the join which would be left join, since I wanted to fetch all ParentObjects regardless of owning childOne or ChildTwo objects.
final Join<ParentObject, ChildOne> joinchildOne =
root.join("childOne", JoinType.LEFT);
final Join<ParentObject, ChildTwo > joinchildTwo =
root.join("childTwo", JoinType.LEFT);
Great, now you have to choose if you need to join or fetch.To optimize the query and the memory, you should establish the relations as Lazy (#ManyToMany (fetch = FetchType.LAZY)), so you will only bring the objects that you demand.
The main difference is that Join defines the crossing of tables in a variable and allows you to use it, to extract certain fields in the select clause, for example, on the other hand, fetch makes it feed all the objects of that property. On your example,
a select from parent with join of children (once the relation is set to lazy) would only bring initialized objects of type parent, however if you perform a fetch, it would bring the parent and child objects initialized.
Another modification I would make is to change the type of the identifier to non-primitive, so that it accepts null values, necessary for insertion using sequences

JPA: Update mapping table alone

I have a Project and Employee entities, which has ManyToMany relationship like below.
#Entity
public class Project {
#Id #GeneratedValue
private int projectId;
private String projectName;
// has some additional columns
#ManyToMany(mappedBy = "projects")
private List<Employee> emp = new ArrayList<Employee> ();
....
.....
}
#Entity
public class Employee {
#Id #GeneratedValue
private int id;
private String firstName;
private String lastName;
#ManyToMany(cascade=CascadeType.ALL)
List<Project> projects = new ArrayList<Project> ();
....
....
}
When I use above entities, JPA create a mpping table 'Employee_Project' like below.
create table Employee_Project (emp_id integer not null, projects_projectId integer not null)
My question is, whenever new employee is added, I want to update both employee table and Employee_Project mapping table only, assume I know project id that I would like to map this employee to. (without touching project table/entity, I mean why should I provide complete project object, while saving employee entity alone, how can I do this via jpa?)
You don't need to provide the entire Project object. Use EntityManager.getReference(projectId) or JpaRepository.getOne(projectId).
Those methods will create a proxy object with the appropriate id, rather than loading the entire Project entity from the data store.
EDIT Your service method should look pretty much like the following:
#Transactional
public void createEmployee(Employee employee, Long projectId) {
employee.setProjects(List.of(projectRepository.getOne(projectId));
employeeRepository.save(employee);
}
As a side note, CascadeType.ALL (in particular, because it includes CascadeType.MERGE and CascadeType.REMOVE) doesn't make sense for #ManyToMany. Unless you're planning to create a Project by creating an Employee, CascadeType.PERSIST makes no sense, either.

Is the domain model/JPA entity model supposed to create a well-designed database table structure?

Let's assume the domain model of an application that is supposed to be built from scratch is described as follows:
A Person might live at an address. A Person can own multiple cars.
If I had to design the database first, I would probably come up with the following database design (normalization, cascading, etc. are not supposed to play a major role for my concrete question).
Person (id, name)
Address (id, street, zip, city, person_id)
Car (id, manufacturer, yearBuilt, color, person_id)
I have mainly followed standard design concepts (e.g. described in this link http://db.grussell.org/section006.html).
As you can see the address table has a foreign key to the person table as the person - address relationship can be considered optional.
The fact that a person can own multiple cars is implemented by putting a foreign key to a person in the car table. I think this is the standard way of modelling 1..m relationships.
If I had to design the domain model first, I would probably come up with the following design:
public class Person {
private String name;
private Address address;
private List<Car> cars;
// Getters and setters
}
public class Address {
private String street;
private String zip;
private String city;
// Getters and setters
}
public class Car {
private String color;
private Date yearBuilt;
// Getters and setters
}
In that domain model, the Person class has all necessary relationships. The Address and Car classes do not need to know anything about their owning Person.
I could now turn these classes into JPA entities by adding #Entity and providing an #Id attribute for every class.
#Entity
public class Person implements Serializable {
#Id
private Long id;
private String name;
#OneToOne
private Address address;
#OneToMany
private List<Car> cars;
public Person() { }
// Getters and setters
}
#Entity
class Address implements Serializable {
#Id
private Long id;
private String street;
private String zip;
private String city;
public Address() { }
// Getters and setters
}
#Entity
class Car implements Serializable {
#Id
private Long id;
private String color;
private Date yearBuilt;
public Car() { }
// Getters and setters
}
If my JPA provider creates the tables according to the provided annotations, the following database structure is created:
Person (id, name, address_id)
Address (id, street, zip, city)
Car (id, manufacturer, yearBuilt, color)
Person_Car (person_id, car_id)
As you can see, that does not correspond to the database structure I would create if I had to design the database first. I see a few flaws in the database model created by the JPA provider:
As the person - address relationship is optional, I would have put the foreign key to a Person into the Address table and not vice versa.
As the standard way of modelling a 1..m relationship is to put the foreign key of the owning class into the detail class, I would have never come up with a relation or association table. Why would I want to have that if the relation is not described by additional attributes?
To join a Person to a Car, the JPA provider needs to perform an additional join to the relation or association table. Does this measurably decrease the performance?
What I could do now is to provide the JPA entity classes with additional fields and/or annotations to strive for the database structure one might expect.
Is it desirable to strive for a domain model/JPA entity design that is able to create an expected database structure (as if database-first-approach was used)? If so, is it acceptable to have a domain model that is different from a domain model one would create intuitively? What are the advantages in designing a domain model/JPA entity model that will create some sort of "best practice" database structure?
Update the mapping from Person to Car as below:
#OneToMany
#JoinColumn(name = "person_id")
private List<Car> cars;
the DDL generator of your JPA provider should then create the desired table structure.

Ebean ManyToOne Mapping CRUD

I have two Entities Transaction and Category with ManyToOne mapping. So many transaction can fall into have category.
#Entity
class Transaction extends Model{
#Id
public Long id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="cat_id", referencedColumnName="cat_id")
public Category cat;
}
#Entity
class Category extends Model{
#Id
#Column(name="cat_id")
public Long catId;
#Column(unique=true)
public String catName;
#ManyToOne
public List<Transaction> transactions
}
Now, when I add two transactions with same catName twice, it throws Unique constraint failure on catName. Is there any way I can instruct Ebean to merge Category, if CatName already exists (instead of always trying to insert)?
Also is this mapping approach correct, considering following:
If I delete Transaction, corresponding Category should not be deleted as it may be referenced by other Transactions.
Thanks for any help!
I think you have wrong annotation on Category model. If you want to list all Transaction data corresponded to any Category data. You should mark this with #OneToMany or #ManyToMany. As you marked your Transaction relation with Category as Many-To-One relationship, meaning that every Transaction has one Category associated to.
// This means every transaction has exactly one category associated
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="cat_id", referencedColumnName="cat_id")
public Category cat;
The relationship between Category with Transaction should be One-To-Many. The code below is a guidance how to fix your model:
#Entity
#Table(name = "category")
public class Category extends Model {
#Id
#Column(name="cat_id")
public Long catId;
#Column(unique=true)
public String catName;
// This means one category can have many transaction associated
#OneToMany(mappedBy = "cat")
public List<Transaction16507336> transactions;
}
It should allow you to save different Transaction object with same Category. Hope it is useful for you friend. :)
Update
The Category and Transaction model now have bi-directional relationship, this means if you have Category object you can also have Transaction object associated to, and vice versa. To save your model, you can follow this approach :
Category cat1 = Ebean.find(Category.class, 1L); // fetch category that exsist
Transaction t1 = new Transaction(); // this is new transaction
t1.cat = cat1; // cat1 category
t1.save();
Transaction t2 = new Transaction(); // this is new transaction
t2.cat = cat1; // cat1 category
t2.save();
Note: This reference may useful for you.

Single Table Inheritance Query

i have an existing table for TransactionLogs which is either links to a External or to a InternalType. the id's corresponding to the cash adjustment & game transaction are stored in a single column called transaction id and a separate column called type indicates which table is it linked to
Because of the nature of the existing table, i mapped it in a single table inheritance:
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.INTEGER)
public class TransLog implements Serializable {
#Id
#GeneratedValue
private Long id;
private Integer type;
// getters and setters
}
#Entity
public class InternalAdjustmentTransLog extends TransLog {
#ManyToOne
#JoinColumn(name = "TransID", nullable = false)
private InternalAdjustmentRecord internalAdjustmentRecord;
// getters and setters
}
#Entity
public class ExternalTransLog extends TransLog {
#ManyToOne
#JoinColumn(name = "TransID", nullable = false)
private ExternalAdjustmentRecord externalAdjustmentRecord;
}
each of these two subclasses has their subclasses with defined descriminator values..
With the setup given above, there are instances that i need to get a unified data of both
internal and external records. What is the best way to accomplish this? at first i thought it would be enough to use the TransLog as the root class for the query (i'm using jpa criteria). however, i need to get TransId (which are defined in the subclasses and points to 2 different objects of no relationship).
Thanks.
You can make abstract method in TransLog that returns what you need and implement it in both subclasses.