JPA Entity for View containig joins and aliases - java

I have the following query using which I want to create an entity class for the columns which I am retrieving from the query.
select e.emp_id,
c.company_code,
mg.emp_id as mangaer_code
from employee e
left join company c on e.emp_id = c.emp_id
left join manager mg on e.emp_id = c.emp_id = mg.emp_id
How to create an entity class from these columns and what variables are needed to take it in entity class to refer to these columns?

View is a virtual table based on the result-set of an SQL statement or a function and JPA treats it as a regular table. Create a entity and use JPA annotations as below
#Entity
#Immutable
#Table(name = "employee_view")
public class EmployeeView{
//define the required columns from view here
}
For more details, refer to this article that I found https://medium.com/#jonathan.turnock/exposing-subset-view-of-the-database-with-a-jpa-repository-over-rest-5b9d6e07344b

Related

Hibernate #Formula which return collection

I'm using a legacy database. In my example, we retrieve a product which have some characteristics. In the db, we can find a product table, a characteristic table and a jointable for the manyToMany association.
The only field i need is the label of the characteristics. So, my Product entity will contains a list of characteristics as String. I would like to not create to many entities in order to not overload my sourcecode. Let's see the example :
#Entity
#Table(name = "product")
public class Product implements Serializable {
#Id
#Column(name = "id")
private Long id;
// all field of Product entity
#ElementCollection(targetClass = String.class)
#Formula(value = "(SELECT characteristic.label FROM a jointable JOIN b characteristic ON jointable.characteristic_id = characteristic.id WHERE jointable.product_id = id)")
private Set<String> characteristics = new HashSet<>();
// Getter / setter
}
To represent my characteristics, i tried to use the association of #Formula and #ElementCollection. As you can see, the names of tables (a and b in the query) does not match with my representation of these datas.
But, when I try to load a product, I get an error like "PRODUCT_CHARACTERISTICS table not found".
Here the generated SQL query executed by hibernate :
SELECT product0_.id AS id1_14_0_,
-- Other fields
characteri10_.product_id AS product_1_15_1__,
(SELECT characteristic.label
FROM a jointable JOIN b characteristic ON jointable.characteristic_id = characteristic.id
WHERE jointable.product_id = id) AS formula6_1__,
FROM product product0_
-- Other Joins
LEFT OUTER JOIN product_characteristics characteri10_ ON product0_.cdprd = characteri10_.product_cdprd
WHERE product0_.id = ?;
In the FROM part, we can refind the call of product_characteristics table (which not exist in the database).
So, my main question is the following : How can I get the list of characterics as entity attribute ? Can I reach this result with #Formula ?
Edit
In other words, i would like to load only one attribute from Many to Many mapping. I found an example here but it works only with the id (which can find in the jointable)
I assume that what you want to achieve here is reducing the amount of data that is fetched for a use case. You can leave your many-to-many mapping as it is, since you will need DTOs for this and I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(Product.class)
public interface ProductDto {
#IdMapping
Long getId();
String getName();
#Mapping("characteristics.label")
Set<String> getCharacteristicLabels();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
ProductDto a = entityViewManager.find(entityManager, ProductDto.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<ProductDto> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!

Spring Boot Model Class only accessing Oracle table when using Synonym

I have a spring boot application and need to create a model class that accesses a database table.
Due to permissions configurations in the db, a SELECT only works using the username in front of the table name or using an Oracle Synonym.
In SQL Developer:
SELECT * FROM MYTABLE; // This doesn't work - ORA-00942: table or view does not exist
SELECT * FROM MYUSER.MYTABLE; // This works
SELECT * FROM MYTABLE_SYNONYM; // This works
In Oracle, MYTABLE_SYNONYM is a Public SYNONYM to MYTABLE.
So the two last SELECTS above are acessing the same MYTABLE table.
In the application:
#Entity
//#Table(name = "MYTABLE") // This doesn't work - ORA-00942: table or view does not exist
//#Table(name = "MYUSER.MYTABLE") // This DOESN'T work - ORA-00942: table or view does not exist
#Table(name = "MYTABLE_SYNONYM") // This works
public class MyClass implements Serializable {
....
}
My question is why #Table(name = "MYUSER.MYTABLE") is generating the "ORA-00942" error if SELECT * FROM MYUSER.MYTABLE works fine in SQL Developer?
In the application, the only way it works is using the Public SYNONYM.
But I wouldn't like to use a Synonym because it can cause confusion and difficulties for the application maintenance as the name is different from the actual table name.
Thanks.
The annotation #Table(name = "MYTABLE") doesn't work because the user that you are using to access the database has access to another schema as the default schema.
The annotation #Table(name = "MYUSER.MYTABLE") doesn't work because this is not the right syntax to access a table in a different schema. You need to use the annotation #Table(name="MYTABLE", schema="MYUSER") that explicitly says to use the schema MYUSER and search for a table named MYTABLE in that schema. This syntax is explained in the javadoc of the annotation Table:
(Optional) The schema of the table.
Defaults to the default schema for user.
The last annotation #Table(name = "MYTABLE_SYNONYM") because somebody defined a synonim MYTABLE_SYNONYM to access the table MYTABLE on the schema MYUSER. This is transparent from the point of view of the user accessing the db.

How to query two SQL tables with the same structure using criteria api?

I have an Archive database where there are 2 tables with the same structure, EvntSumaryT which is active and ArchiveEvntSumaryT which is the archived. I want to change my current criteria api code which only queries EvntSumary so that it will fetch data from both tables based on the user selected dates and return the results into a list.
My problem is that their is no Union feature in hibernate-criteria so how would I be able to query both tables at once and combine the results into a list?
Below is the code for my jpa entity classes. I've set up the active table's entity as the parent class and the child as ArchiveEvntSumaryT which extents from it since they share the same fields.
#Entity
#Table(name="EVNT_SUMARY_T")
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class EvntSumaryT {
//fields
//getters and setters
}
#Entity
#Table(name="ARCHIVE_EVNT_SUMARY_T")
public class ArchiveEvntSumaryT extends EvntSumaryT {
}
And this is my criteria api query in the DAO class before archiving the database.
public List<EvntSumaryT> getAllTransaction(SearchCriteria sb) {
//criteria
return ls;
}
How would I be able to query both tables and return the results into a list without the Union function?
I figured it out. Instead of using inhertance to replace the union function I ended up creating a view in the database that's the union of the two tables and mapped the entity to the view.

Returning child entities from a parent entity with JPA join

How can I return a list of entities that has a relationship to a parent in JPA?
I have a User entity that has a #OneToMany mapping on a property named pets. The child entities are of type Pet. It is only a uni-directional relationship.
How can I write a join in JPA that returns all pets given a user?
So you have a couple of options.
You can use the following annotations:
#ManyToOne
#JoinColumn
This is how you would use it.
public class User
{
// your standard fields / columns in database
#OneToMany (Fetch can be of eager/ lazy)
#JoinColumn (name="column to join on", referencedColumnName="column to join on in parent class")
private List<Pet> pets;
}
public Class Pet
{
//data fields
}
What essentially happens is the list of pets is populated when you are querying for the user object.
Using JPA to Query the DB.
So i am guessing that Your user would have some sort of id and the pet table would have some sort of Id to the user that are linked.
So we would do the following
Select * from user where user_id = ?;
this will essentially give you the user object
Select * from pet where owner_user_id = ?
this will essentially give you all the pets that belong to that user.
Then you can populate your object yourself.
I am not 100% sure of how your table looks like, but I was hoping to give it a stab from just what I would do point of view.

Hibernate #OneToOne with superclass, only retrieve superclass fields on join

I have mapped my inheritance hierarchy in Hibernate using InheritanceType.Single_Table and discriminator columns to distinguish between the different entities. All subclasses of the superclass store their fields into secondary tables. As an example:
#MappedSuperclass
public abstract class Base
{
#Id
private String id;
#Version
private long version;
}
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
public class Parent extends Base
{
#Column(nullable=false)
private BigDecimal value;
}
#Entity
#DiscriminatorValue("child1")
#SecondaryTable(name = "Child1")
public class Child1 extends Parent
{
#Column(table="Child1")
private String name;
}
#Entity
#DiscriminatorValue("child2")
#SecondaryTable(name = "Child2")
public class Child2 extends Parent
{
#Column(table="Child2")
private String name2;
}
I now have an Entity that has a #OneToOne relationship with the Parent class. This Entity only needs to work with the value field from the Parent class. It will never need to work with any fields from any subclass of Parent
#Entity
public class AnotherEntity extends Base
{
#JoinColumn(name="parentId")
#OneToOne(fetch=FetchType.Lazy, optional=true, targetEntity=Parent.class)
private Parent parent;
}
What I want to happen is that only the fields of Parent.class are selected when the relationship to parent is loaded from the database. What I'm seeing is that Hibernate attempts to load all properties of the entities that extend Parent. It also left joins all of the Secondary tables. This is problematic as I have rougly 30 entities that extend Parent. This makes fetching the Parent entity non-viable as the query performs 30 joins.
As an example, this is the type of query I am seeing:
Hibernate:
select
parent.id as id3_0_,
parent_.version as version3_0_,
parent.name1 as name110_3_0_,
parent.name2 as name24_3_0_,
parent.type as type3_0_
from
Parent parent0_
left outer join
Child1 parent0_2_
on parent0_.id=parent0_2_.id
left outer join
Child2 parent0_3_
on parent0_.id=parent0_3_.id
I don't understand why Hibernate decides to select a superset of all properties defined in the subclasses of Parent and join all of the secondary tables? I could understand it joining the secondary table for entity defined by the discriminator value of the parent being referenced, but otherwise I am confused.
My question is, how do I go about achieving my requirement of only having the fields from the Parent class loaded when I retrieve the Parent relationship in the AnotherEntity class?
Thanks.
A secondary table is normally used to map the content of a single entity to two tables. It doesn't allow for lazy/select fetching using standard JPA annotations. You may use a proprietary Hibernate annotation to load it using a separate select, and only if necessary, though. See http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-join:
fetch: If set to JOIN, the default, Hibernate will use an inner join
to retrieve a secondary table defined by a class or its superclasses
and an outer join for a secondary table defined by a subclass. If set
to SELECT then Hibernate will use a sequential select for a secondary
table defined on a subclass, which will be issued only if a row turns
out to represent an instance of the subclass. Inner joins will still
be used to retrieve a secondary defined by the class and its
superclasses.
So setting the fetch attribute of the Hibernate #Table annotation to SELECT will do what you want : an additional select clause will be issued to select the values from just the appropriate secondary table.
If you want lazy fetching, then a secondary table is not what you want. You'll have to do it using associations.

Categories