what to use instead of fetch.EAGER in spring data? - java

I'm working with spring-boot and angular5 , i have this entity in spring :
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Contrat implements Serializable{
#Id #GeneratedValue
private Long id;
private Date dateDebut ;
private Date dateFin ;
#ManyToOne
#JoinColumn(name = "Id_Project")
#JsonBackReference(value="projet-contrat")
private Project project;
#ManyToOne
#JoinColumn(name = "Id_AppUser")
#JsonBackReference(value="appuser-contrat")
private AppUser appUser;
}
A repository :
public interface ContratRepo extends JpaRepository<Contrat,Long> {
public Page<Contrat> findByAppUser(#Param("userApp") AppUser userApp, Pageable pageable);
}
As the fetch.lazy is the default one , when i try to call the method findByAppUser i get as result :
{id: 1, dateDebut: 1526083200000, dateFin: 1526083200000}
Which is normal , what i want for my case is to load also the object 'project' that exists in the entity , but i don't wan't to use the fetch.EAGER , any solution for this goal ?

Your entity is one-many relationship object. If you don't use EAGER, spring data will get the object without related member object. And if you get that with contract.getProject().getName(), then another query will be sent to get that member.
If you log the SQL, you can see that, there will be 2 queries. But if you set the field as EAGER, there will be only 1 query. You can get improvement obviously.
But you should not use EAGER always. If in 90% of time, you just need the Contract object, but no need the project data of it. It is a waste of time to get that. Because in SQL, it will relate 2 tables and get all columns of data.
SO, you should make this decision based on your usage of this entity.
[Updated based on comment]
You can use Query to write your sql expression. for example, I have a method to get the entity with detail:
#Query("select s from Contract s left join fetch s.project pr where s.id = ?1 ")
Contract findOneWithDetail(Long id);
If I need to get the detail in ONE sql, I can use this method. If I don't need the project detail, I just use findOne(Long id), which is provided interface.
And, if you just want to get some columns, you need to define a DTO, with a constructor, and write your method like this:
#Query("SELECT NEW com.mypackage.dto.ContractDTO(s.id, s.name, s.status) FROM Contract AS s WHERE s.status = ?1")
List<ContractDTO> findDTOAllByStatus(String status);

Provide the query in your repo method, e.g. (syntax may be wrong, just show you the idea)
public interface ContratRepo extends JpaRepository<Contrat,Long> {
#Query(query="from Contrat c left join fetch c.project " +
"where c.userApp = :userApp")
public Page<Contrat> findByAppUser(#Param("userApp") AppUser userApp, Pageable pageable);
}

Related

Joining two tables without JPQL

I have to MySQL tables TICKET-is the parent and USER-is the child, in a many-to-one relationship.
=TICKET=
PK(ID)
summary
message
FK(user_id) references USER(user_id)
=USER=
PK(ID)
email
password
And the JPA entities
#Entity
class TICKET {
#Id
private Integer ID;
private String summary;
private String message;
#ManyToOne
#JoinColumn(name="user")
private USER user;
}
#Entity
class USER {
#Id
private Integer ID;
private String email;
private String password;
}
If i make a query to get a ticket by ID it will return also the user information (USER.ID, USER.email, USER.password) which is not good.
ticketsCrudRepository.findById(ticketId);
What i want is to get a table that looks like this:
TICKET.ID | summary | message | USER.email
I know how to do it in MySQL but JPA it's to much for me. I don't want to use JPQL or native query language.
Any suggestions?
When you fetch a Ticket you also get a User since #ManyToOne by default has FetchType.EAGER. You can change this by changing the anotation to #ManyToOne(fetch = FetchType.LAZY)
To do the search you chould try somethig like
public List<Object[]> getTikcetsForUser(final User user) {
String hql = "select t.id, t.summary, t.message, u.email "
+ "from Tikcet t, User u "
+ "where ticket.user = :user";
Query<Object[]> query = getSession().createQuery(hql, Object[].class);
query.setParameter("user", user);
return query.getResultList();
}
The returned List will contain arrays with 4 fields (t.id, t.summary, t.message, u.email).
Please let me know if you find this useful.
:)
The solution i was looking for was Spring Data JPA Projections. They can be interfaces or classes with getters that match the columns you want to get from the database. For detailed informations check the Spring Framework documentation here.
Using Spring Data Projections is one option, but you will at some point run into the limitations it has. If you reach that point, you can look into 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(TICKET.class)
public interface TicketDto {
#IdMapping
Long getId();
String getName();
UserDto getUser();
#EntityView(USER.class)
interface UserDto {
#IdMapping
Long getId();
String getEmail();
}
}
Or even simpler in your case
#EntityView(TICKET.class)
public interface TicketDto {
#IdMapping
Long getId();
String getName();
#Mapping("user.email")
String getUserEmail();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
TicketDto a = entityViewManager.find(entityManager, TicketDto.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

JPA unidirectional #OneToOne relationship with shared primary key always trigger a secondary query even if fetchType is EAGER

I am building a blog system, and like to provide the upvote/downvote feature for the blog. Since the vote count number of blog should be persisted, i choose to use MySQL to act as the data store. And i use Spring JPA(Hibernate) to do the ORM job. Here's my data objects:
class Blog{
// ...
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(optional = false, fetch = FetchType.EAGER)
#PrimaryKeyJoinColumn
private BlogVoteCounter voteCounter;
}
And the counter class:
#Entity
public class BlogVoteCounter extends ManuallyAssignIdEntitySuperClass<Long> {
#Id
private Long id;
private Integer value;
}
The reason why i separate the BlogVoteCounter from Blog is that i think the voteCount field will be modified by a totally different frequency comparing to other fields of Blog, since i want to use cache to cache the Blog, following this guide, i choose to separate them.
However, since the VoteCount field might be always needed when return the Blog object to the front end, and to avoid the n+1 problem, i declared the BlogVoteCounter field in Blog class with EAGER fetch type.
I've already seen this article. Thus according to my personal comprehension, i use unidirectional relationship and only declare OneToOne in the Blog side.
However, when i examine the query, it turns out that jpa will still trigger a secondary query to retrieve BlogVoteCounter from database without simply using a join when use findAll method on BlogRepository.
select
blogvoteco0_.id as id1_2_0_,
blogvoteco0_.value as value2_2_0_
from
blog_vote_counter blogvoteco0_
where
blogvoteco0_.id=?
So how should i config, to always make the BlogVoteCounter field in Blog be fetched eagerly.
The usage of ManuallyAssignIdEntitySuperClass is following the Spring JPA doc, since i manually assign id for BlogVoteCounter class.
#MappedSuperclass
public abstract class ManuallyAssignIdEntitySuperClass<ID> implements Persistable<ID> {
#Transient
private boolean isNew = true;
#Override
public boolean isNew() {
return isNew;
}
#PrePersist
#PostLoad
void markNotNew(){
this.isNew = false;
}
}
And the BlogRepository is derived from JpaRepository
public interface BlogRepository extends JpaRepository<Blog, Long>{
// ...
}
I trigger the query by using findAll method, but using findById or other conditional query seems no difference.
When to fetch vs How to fetch : fetchType defines when to fetch the association ( instantlyvs later when someone access) the association but not how to fetch the association(i.e second select vs join query). So from JPA Spec point of view, EAGER means dont wait until someone access that field to populate it but JPA provider is free to use JOIN or second select as long as they do it immediately.
Even though they are free to use join vs second select, still I thought they should have optimised for join in the case of EAGER. So interested in finding out the logical reasoning for not using the join
1. Query generated for repository.findById(blogId);
select
blog0_.id as id1_0_0_,
blog0_.vote_counter_id as vote_cou2_0_0_,
blogvoteco1_.id as id1_1_1_,
blogvoteco1_.value as value2_1_1_
from
blog blog0_
inner join
blog_vote_counter blogvoteco1_
on blog0_.vote_counter_id=blogvoteco1_.id
where
blog0_.id=?
2. Updated Mapping
public class Blog {
#Id
private Long id;
#ManyToOne(optional = false, cascade = ALL, fetch = FetchType.EAGER)
#PrimaryKeyJoinColumn
private BlogVoteCounter voteCounter;
public Blog() {
}
public Blog(Long id, BlogVoteCounter voteCounter) {
this.id = id;
this.voteCounter = voteCounter;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public BlogVoteCounter getVoteCounter() {
return voteCounter;
}
public void setVoteCounter(BlogVoteCounter voteCounter) {
this.voteCounter = voteCounter;
}
}
3. Issues with current Mapping
As per your mapping, it is impossible to create blog and votecounter as it causes a chicken and egg problem.
i.e
blog and votecounter need to share the same primary key
blog's primary key is generated by database.
so in order to get the primary key of blog and assign it to votecounter as well, you need to store blog first
but the #OneToOne relationship is not optional, so you cannot store blog first alone
4.Changes
Either need to make the relationship optional so blog can be stored first, get the id, assign to BlogVoteCounter and save the counter
Or Don't auto generate Id and manually assign the id so blog and votecounter can be saved at the same time.(I have gone for this option but you can do first option)
5.Notes
default repository.findAll was generating 2 queries so I overridden that method to generate one join query
public interface BlogRepository extends JpaRepository<Blog, Long> {
#Override
#Query("SELECT b from Blog b join fetch b.voteCounter ")
List<Blog> findAll();
}
select
blog0_.id as id1_0_0_,
blogvoteco1_.id as id1_1_1_,
blog0_.vote_counter_id as vote_cou2_0_0_,
blogvoteco1_.value as value2_1_1_
from
blog blog0_
inner join
blog_vote_counter blogvoteco1_
on blog0_.vote_counter_id=blogvoteco1_.id

Select only some columns from a table

Is there a way to select only some columns from a table using jpa?
My tables are huge and I am not allowed to map all the columns in my entities. I tried to create an entity (as a side note, I don't have PKs in my tables):
#Entity
#Table(name = "SuperCat")
#Getter
#Setter
public class Cat{
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#Column(name="nameCat")
private String name;
}
and then in my repository to
public interface CatRepository extends
CrudRepository<Cat, Long> {
#Query(
"SELECT name FROM Cat")
Page<Cat> getAlCats(Pageable pageable);
This is only a simple example, but the idea is the same. I have searched a lot and I found projections, but there you need to map the whole table, then I found native queries, but still doesn't apply. I know I can return an Object and the other solution is to use query with NEW and create my own object (no #entity, like a pojo). But is there a way that I can do this using jpa, to be able to use repository and services, if I am creating my own pojo then i will create a #transactional class put the queries (with NEW) there and this is it. I don't like this approach and I don't think that the jpa does't allow you to select only some columns, but I didn't find a proper way.
Maybe you will ask what is the result if I am doing like this:
I get this error: "Cannot create TypedQuery for query with more than one return using requested result type [java.lang.Long]"
(For new queries, I am talking about : http://www.java2s.com/Tutorials/Java/JPA/4800__JPA_Query_new_Object.htm maybe I was not clear)
You can do the same by using below approach.
Just create a constructor in entity class with all the required parameters and then in jpa query use new operator in query like below.
String query = "SELECT NEW com.dt.es.CustomObject(p.uniquePID) FROM PatientRegistration AS p";
TypedQuery<CustomObject> typedQuery = entityManager().createQuery(query , CustomObject.class);
List<CustomObject> results = typedQuery.getResultList();
return results;
And CustomObject class should look like below with the constructor.
public class CustomObject {
private String uniquePID;
public CustomObject(String uniquePID) {
super();
this.uniquePID = uniquePID;
}
public String getUniquePID() {
return uniquePID;
}
public void setUniquePID(String uniquePID) {
this.uniquePID = uniquePID;
}
}
spring-data-jpa projection not need to map the whole table, just select the necessary fileds :
// define the dto interface
public interface CatDto {
String getName();
// other necessary fields
...
}
#Query(value = "select c.name as name, ... from Cat as c ...)
Page<CatDto> getAllCats(Pageable pageable);
By this way, CatDto is an interface and it only includes some fileds part of the whole table. Its fields name need to match the select field's alias name.

Hibernate: projection JPQL query to DTO issue

To start with, I'll list three models that I work with in a query
ProductEntity:
#Entity
#Table(name = "product")
public class ProductEntity extends BaseEntity {
//some fields
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "owner_id")
private PartnerEntity owner;
#OneToMany(
mappedBy = "product",
fetch = FetchType.LAZY
)
private List<StockProductInfoEntity> stocks;
}
PartnerEntity:
#Entity
#Table(name = "partner")
public class PartnerEntity extends AbstractDetails {
//some fields
#OneToMany(
mappedBy = "owner",
fetch = FetchType.LAZY
)
private List<ProductEntity> products;
}
and StockProductInfoEntity:
#Entity
#Table(name = "stock_product")
public class StockProductInfoEntity extends BaseEntity {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "product_id")
private ProductEntity product;
//other fields
#Column(name = "rest")
private int rest;
}
And i want to fetch from database product with partner + calculate count in all stocks.
For convenience, I created a simple DTO:
#Getter
#AllArgsConstructor
public class ProductCountDTO {
private ProductEntity productEntity;
private int count;
//hack for hibernate
public ProductCountDTO(ProductEntity productEntity, long count) {
this.productEntity = productEntity;
this.count = (int) count;
}
}
and write JPQL query in JPA repository:
#Query("select new ru.oral.market.persistence.entity.product.util.ProductCountDTO(p, sum(stocks.rest))"+
" from ProductEntity p" +
" join fetch p.owner owner" +
" join p.stocks stocks" +
" where p.id = :id" +
" group by p, owner")
Optional<ProductCountDTO> findProductWithCount(#Param("id") long id);
But my application did not even start because of a problem with the query validation. I get this message:
Caused by: org.hibernate.QueryException: query specified join
fetching, but the owner of the fetched association was not present in
the select list
Very strange, but I tried to replace join fetch -> join.
And I understood why I got this error, hibernate made such a query to the database:
select
productent0_.id as col_0_0_,
sum(stocks2_.rest) as col_1_0_
from
product productent0_
inner join
partner partnerent1_
on productent0_.owner_id=partnerent1_.user_id
inner join
stock_product stocks2_
on productent0_.id=stocks2_.product_id
where
productent0_.id=?
group by
productent0_.id ,
partnerent1_.user_id
But why does he only take the product id and nothing else?
This query with Tuple work and get all fields from product and partner
#Query("select p, sum(stocks.rest) from ProductEntity p" +
" join fetch p.owner owner" +
" join p.stocks stocks" +
" where p.id = :id" +
" group by p, owner")
Optional<Tuple> findProductWithCount(#Param("id") long id);
And this produced native query what i want:
select
productent0_.id as col_0_0_,
sum(stocks2_.rest) as col_1_0_,
partnerent1_.user_id as user_id31_12_1_,
productent0_.id as id1_14_0_,
productent0_.brand_id as brand_i17_14_0_,
productent0_.commission_volume as commissi2_14_0_,
productent0_.created as created3_14_0_,
productent0_.description as descript4_14_0_,
productent0_.height as height5_14_0_,
productent0_.length as length6_14_0_,
productent0_.long_description as long_des7_14_0_,
productent0_.name as name8_14_0_,
productent0_.old_price as old_pric9_14_0_,
productent0_.owner_id as owner_i18_14_0_,
productent0_.pitctures as pitctur10_14_0_,
productent0_.price as price11_14_0_,
productent0_.status as status12_14_0_,
productent0_.updated as updated13_14_0_,
productent0_.vendor_code as vendor_14_14_0_,
productent0_.weight as weight15_14_0_,
productent0_.width as width16_14_0_,
partnerent1_.about_company as about_co1_12_1_,
partnerent1_.bik as bik2_12_1_,
partnerent1_.bank_inn as bank_inn3_12_1_,
partnerent1_.bank_kpp as bank_kpp4_12_1_,
partnerent1_.bank as bank5_12_1_,
partnerent1_.bank_address as bank_add6_12_1_,
partnerent1_.checking_account as checking7_12_1_,
partnerent1_.correspondent_account as correspo8_12_1_,
partnerent1_.company_name as company_9_12_1_,
partnerent1_.company_inn as company10_12_1_,
partnerent1_.company_kpp as company11_12_1_,
partnerent1_.ogrn as ogrn12_12_1_,
partnerent1_.okato as okato13_12_1_,
partnerent1_.actual_address as actual_14_12_1_,
partnerent1_.director as directo15_12_1_,
partnerent1_.full_name as full_na16_12_1_,
partnerent1_.legal_address as legal_a17_12_1_,
partnerent1_.short_name as short_n18_12_1_,
partnerent1_.country as country19_12_1_,
partnerent1_.discount_conditions as discoun20_12_1_,
partnerent1_.discounts as discoun21_12_1_,
partnerent1_.logo as logo22_12_1_,
partnerent1_.min_amount_order as min_amo23_12_1_,
partnerent1_.min_shipment as min_shi24_12_1_,
partnerent1_.min_sum_order as min_sum25_12_1_,
partnerent1_.own_delivery as own_del26_12_1_,
partnerent1_.own_production as own_pro27_12_1_,
partnerent1_.phones as phones28_12_1_,
partnerent1_.return_information as return_29_12_1_,
partnerent1_.site as site30_12_1_
from
product productent0_
inner join
partner partnerent1_
on productent0_.owner_id=partnerent1_.user_id
inner join
stock_product stocks2_
on productent0_.id=stocks2_.product_id
where
productent0_.id=?
group by
productent0_.id ,
partnerent1_.user_id
But it's not very convenient.
Why DTO projection doesn't work correctrly, but tuple works fine?
Because that's how Hibernate is currently implemented.
Because you used an entity in the DTO Projection, which as the name implies, it should be used for DTOs, not entities, Hibernate is going to assume that you want to GROUP BY by the identifier because it should not GROUP BY all entity properties.
The Tuple is broken and it will only work in MySQL, but not in Oracle or PostgreSQL since your aggregate query selects columns that are not present in the GROUP BY clause.
However, this is not demanded to work according to the JPA specs. Nevertheless, you should still provide a replicating test case and open an issue so that the behavior is the same for both situations.
Anyway, once fixed, it will still GROUP BY identifier. If you want to select entities and group by as well, you will have to use a native SQL query along with the Hibernate ResultTransformer to transform the ResultSet into a graph of objects.
More, fetching entities and aggregations is a code smell. Most likely, you need a DTO projection or a read-only view.
Entities should only be fetched when you want to modify them. Otherwise, a DTO projection is more efficient and more straightforward as well.
Since Vlad already explained the why, I will focus on an alternative solution. Having to specify all attributes that you are really interested in in the SELECT clause and the GROUP BY clause is a lot of work.
If you used Blaze-Persistence Entity Views on top of Hibernate, this could look like the following
#EntityView(ProductEntity.class)
public interface ProductCountDTO {
// Or map the ProductEntity itself if you like..
#Mapping("this")
ProductView getProduct();
#Mapping("sum(stocks.rest)")
int getCount();
}
#EntityView(ProductEntity.class)
public interface ProductView {
// Whatever mappings you like
}
With the Spring Data or DeltaSpike Data integration you can even use it like that
Optional<ProductCountDTO> findById(long id);
It will produce a JPQL query like the following
SELECT
p /* All the attributes you map in ProductView */,
sum(stocks_1.rest)
FROM
ProductEntity p
LEFT JOIN
p.stocks stocks_1
GROUP BY
p /* All the attributes you map in ProductView */
Maybe give it a shot? https://github.com/Blazebit/blaze-persistence#entity-view-usage
The magic is that Blaze-Persistence handles the GROUP BY automatically when encountering an aggregate function by putting every non-aggregate expression you use into the GROUP BY clause if there is at least one aggregate function used.
When using Entity Views instead of entities directly, you won't be facing the join fetch problems as Entity Views will only put the fields you actually map into the resulting SELECT clause of the JPQL and SQL.
Even if you used entities directly or via the ProductCountDTO, the query builder used behind the scenes handles selects of entity types in case of a group by gracefully, just as you'd expect it from Hibernate.

How to create Many-One Mapping in hibernate?

I want to create Many-One Mapping between two tabels, Expense(ID, NAME, CATEGORY) and
Category(ID, NAME).
In my class i have created a field 'Category category' and its setters and getters.
I did them after seeing some stuff from internet. What are all the changes i have to do in my Category.java class. For now, its looks like,
public class Category{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int catId;
private String catName;
public Category() {
}
public int getCatId() {
return this.catId;
}
public void setCatId(int catId) {
this.catId = catId;
}
public String getCatName() {
return this.catName;
}
public void setCatName(String catName) {
this.catName = catName;
}
}
I dont want to do mappings with xml config. I think, annotations is good for a beginner like me.
And my Old! SQL query looks like,
SELECT EXPENSES.EXPNS_ID, EXPENSES.CAT_ID, EXPENSES.NAME, CATEGORY.CAT_NAME FROM EXPENSES INNER JOIN CATEGORY ON EXPENSES.CAT_ID = CATEGORY.CAT_ID WHERE USER_NAME="+currentUserName
How to use inner join in Hibernate?
Any Suggestions!!
Thanks!
Update
Thanks for all answerers,
I tried what you told and it returns a empty list.
To, test i set the 'userName=Tamil' which is in the table.
The query generated by Hibernate is looks like below,
select expens0_.expnsId as expnsId1_, expens0_.catId as catId1_, expens0_.category_catId as category7_1_, expens0_.userName as userName1_ from Expens expens0_ inner join Category category1_ on expens0_.category_catId=category1_.catId where expens0_.userName=?
As a beginner, i have some doubts in JPQL, I want catName from Category[catId, catName] table. And the catId is also available in Expens[expnsId, catId, userName].
By adding the below lines in Expens.java class, how it will give me catName along with the other variables in the Expens table.
#ManyToOne
private Category category
// getters, setters
I cant able to understand it. Without understanding this i cant move further, i have to give more mappings in my project. If clear with this mapping, i can move to the rest with confidence.
The query i used is pascal's version: Query query = hSession.createQuery("SELECT e FROM Expens e JOIN e.category c WHERE e.userName = :userName").setParameter("userName", userName);
For me, the query generated by hibernate is looks like same as my Old SQl query. I cant able to find problem here.
Actually, a big part of the documentation that would be useful in your case is located in the Hibernate Annotations Reference Guides (links provided below). Reading it would be very worth it.
That being said, regarding your specific question, the simplest possible mapping would be:
#Entity
public class Expense {
#Id #GeneratedValue
private Long;
#ManyToOne
private Category category
// getters, setters
...
}
That's all.
If you want to make it bi-directional, you'll have to add a OneToMany on the other side (and don't forget the mappedBy element since the association is bidirectional):
#Entity
public class Category {
#Id #GeneratedValue
private Long id;
#OneToMany(mappedBy="category")
private Set<Expense> expenses = new HashSet<Expense>();
....
}
And a possible JPQL query would be:
SELECT e FROM Expense e JOIN e.category c WHERE e.username = :username
Update: Hibernate and JDBC are different. With Hibernate, you need to think objects and the above HQL query (which was more an example) will actually return a List<Expense>. To get a category name, iterate over the results and navigate through the association. For example:
List<Expense> expenses = ... // some code to retrieve a list by username
for (Expense expense : expenses) {
System.out.println(expense.getCategory().getName());
}
References
2.2. Mapping with JPA (Java Persistence Annotations)
2.2.5.2. Many-to-one
As Bozho suggested,
#ManyToOne(fetch=FetchType.EAGER) // Gonna be eager by default anyway
#JoinColumn(name="CATEGORY_ID")
private Category category;
Plus this in your Category class to make it bidirectional,
#OneToMany(mappedBy="category")
private List<Expense> expense;
You need not do an inner join like that. When you query the expense, the related category will automatically get loaded eagerly, most likely using join.
In your Expense class have:
#ManyToOne
#JoinColumn(name="CATEGORY_ID")
private Category category
As pointed in the comments, if you need to access all expenses in a given category, i.e. have the one-to-many relationship, you can have:
#OneToMany
private List<Expense> expenses;
I, for example, prefer to use as little #OneToMany mappings as possible - you'd have to manager eager/lazy loading, at some point limiting the number of results, etc. For them I tend to use HQL queries that fetch the subset of objects (expenses in your case) that I need.

Categories