I'm curious to find a solution for this but couldn't find anything relatable and useful so far.
Lets say user have two transactions for 18/01/2023
I want to have a heading for example like separate <div> and to pass today date and each transaction from today, and below down for example 15/01/2023 because user also have a transactions on that date.
This is an example, as you can see I have today section because user made a transaction on today date, also for yesterday and then back on January 14, so I want to separate transactions for each that like that. Example
This is Transaction class:
#Entity
#Table(name = "transaction")
public class Transaction {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "transaction_id")
private Long id;
#Column(name = "user_id", nullable = false)
private Long userId;
#Column(name = "wallet_name", nullable = false)
private String walletName;
#NotNull(message = "Please, insert a amount")
#Min(value = 0, message = "Please, insert a positive amount")
private Double amount;
private String note;
#DateTimeFormat(pattern = "yyyy-MM-dd")
#Column(name = "date")
private LocalDate date;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "wallet_id", nullable = false)
private Wallet wallet;
#Enumerated(EnumType.STRING)
#Column(name = "transaction_type", columnDefinition = "ENUM('EXPENSE', 'INCOME')")
private TransactionType transactionType;
#Nullable
#Enumerated(EnumType.STRING)
#Column(name = "expense_categories", columnDefinition = "ENUM('FOOD_AND_DRINK', 'SHOPPING', 'TRANSPORT', 'HOME'," +
" 'BILLS_AND_FEES', 'ENTERTAINMENT', 'CAR', 'TRAVEL', 'FAMILY_AND_PERSONAL', 'HEALTHCARE'," +
" 'EDUCATION', 'GROCERIES', 'GIFTS', 'BEAUTY', 'WORK', 'SPORTS_AND_HOBBIES', 'OTHER')")
private ExpenseCategories expenseCategories;
#Nullable
#Enumerated(EnumType.STRING)
#Column(name = "income_categories", columnDefinition = "ENUM('SALARY', 'BUSINESS', 'GIFTS', 'EXTRA_INCOME', 'LOAN', 'PARENTAL_LEAVE', 'INSURANCE_PAYOUT', 'OTHER')")
private IncomeCategories incomeCategories;
I created a new class that will act as group and that is like this:
class TransactionGroup {
private LocalDate date;
private List<Transaction> transactions;
/* Getters and setters */
}
And Thymeleaf:
<div th:each="singleGroup : ${transactionGroup}">
<h1 th:text="${singleGroup .date}"></h1>
<div th:each="singleTrans : ${singleGroup.transactions}">
<h2>Amount: <span th:text="${singleTrans .amount}"></span></h2><br>
<h2>Note: <span th:text="${singleTrans .note}"></span></h2><br>
<h2>Wallet name: <span th:text="${singleTrans .walletName}"></span></h2><br>
<h2>Expense Category: <span th:text="${singleTrans .expenseCategories}"></span></h2><br>
<h2>IncomeCategory: <span th:text="${singleTrans .incomeCategories}"></span></h2>
<div>
</div>
</div>
</div>
And this is controller:
#GetMapping("/userTransactions/{user_id}")
public String getUserTransactions(#PathVariable("user_id") long user_id, TransactionGroup transactionGroup, Model model) {
List<Transaction> transactions = transactionRepository.getTransactionsByUserId(user_id);
//create a TransactionGroup list
List<TransactionGroup> transactionByDate = new ArrayList<>();
//create a list that will hold all transactions for a day
List<Transaction> transOnSingleDate = new ArrayList<>();
//initialize currDate with the first transaction date
LocalDate currDate = transactions.get(0).getDate();
//create a TransactionGroup
TransactionGroup transGroup = new TransactionGroup();
//loop through your transactions and populate the wrapper list
for(Transaction t : transactions){
//create a new transaction group if the date has changed
if(!currDate.isEqual(t.getDate())){
//fill the wrapper list before creating a new list
transGroup.setDate(currDate);
transGroup.setTransactions(transOnSingleDate);
transactionByDate.add(transGroup);
//create new TransactionGroup and List<Transaction> for a new date
transGroup = new TransactionGroup();
transOnSingleDate = new ArrayList<>();
}
transOnSingleDate.add( t );
currDate = t.getDate();
}
//add the final list
transGroup.setDate(currDate);
transGroup.setTransactions(transOnSingleDate);
transactionByDate.add(transGroup);
model.addAttribute("transactionGroup", transactionByDate);
return "transactions";
}
You can see that I populate here transaction list in TransactionGroup by transactions from entity Transaction:
transactionGroup.setTransactions(transactionService.findDistinctIdByUserId(userId));
And on page I can see transactions, but I cant see a date how I want, I cant even see date, date is not displayed, because I didn't populate a date field on class TransactionGroup with date from Transaction class. How I can get a transaction date from each transaction that is created?
I guess I need to populate it somehow like transactionGroup.setTransactions... but now like transactionGroup.setDate... but Date is not a list type, so there is a problem.
Its obivous that if I try with transactionGroup.setDate(transaction.getDate); returning null
SOUT LOGS:
transGroup TransactionGroup{date=2023-01-01, transactions=null}
transactionByDate [TransactionGroup{date=2023-03-01, transactions=[Transaction{id=18, userId=1, walletName='Dailyk', amount=4.0, note='Cetvrta transakcija', date=2023-03-01, wallet=com.budgettracker.demo.userProfile.models.Wallet#68e4f813, transactionType=INCOME, expenseCategories=null, incomeCategories=BUSINESS}]}, TransactionGroup{date=2023-02-01, transactions=[Transaction{id=17, userId=1, walletName='Dailyk', amount=3.0, note='Treca transakcija', date=2023-02-01, wallet=com.budgettracker.demo.userProfile.models.Wallet#68e4f813, transactionType=INCOME, expenseCategories=null, incomeCategories=EXTRA_INCOME}]}, TransactionGroup{date=2023-01-01, transactions=[Transaction{id=15, userId=1, walletName='Dailyk', amount=1.0, note='Prva transkacija', date=2023-01-01, wallet=com.budgettracker.demo.userProfile.models.Wallet#68e4f813, transactionType=INCOME, expenseCategories=null, incomeCategories=SALARY}, Transaction{id=16, userId=1, walletName='Dailyk', amount=2.0, note='Druga transkacija', date=2023-01-01, wallet=com.budgettracker.demo.userProfile.models.Wallet#68e4f813, transactionType=INCOME, expenseCategories=null, incomeCategories=GIFTS}]}]
This can be done in many ways. For instance, you can define a wrapper list ( List<List<Transaction>> or List<TransactionGroup>) where the contained list(s) will contain all the transactions on a given day. It would also make sense to create a native query to retrieve the transactions for a particular user sorted by date.
//your Transaction repository
#Query( value="select * from transaction where user_id = ?1 order by date desc", nativeQuery=true)
List<Transaction> getTransactionsByUserId(Integer userId);
The logic in your controller could then look something like
....
//this list holds all the transactions for a particular user
List<Transaction> transactions = transRepository.getTransactionsByUserId(userId);
//create the wrapper list
List<List<Transaction>> transactionByDate = new ArrayList<>();
//initialize currDate with the first transaction date
LocalDate currDate = transactions.get(0).getDate();
//create a list that will hold transactions for a single date
List<Transaction> transOnSingleDate = new ArrayList<>();
//loop through your transactions and populate the wrapper list
for(Transaction t : transactions){
//create a new list of transactions if the date has changed
if(!currDate.isEqual(t.getDate()){
//fill the wrapper list before creating a new list
transactionByDate.add(transOnSingleDate);
transOnSingleDate = new ArrayList<>();
}
transOnSingleDate.add( t );
currDate = t.getDate();
}
//add the final list
transactionByDate.add(transOnSingleDate);
model.addAtrribute("transByDate", transactionByDate);
or using List<TransactionGroup>
....
//this list holds all the transactions for a particular user
List<Transaction> transactions = transRepository.getTransactionsByUserId(userId);
//create a TransactionGroup list
List<TransactionGroup> transactionByDate = new ArrayList<>();
//create a list that will hold all transactions for a day
List<Transaction> transOnSingleDate = new ArrayList<>();
//initialize currDate with the first transaction date
LocalDate currDate = transactions.get(0).getDate();
//create a TransactionGroup
TransactionGroup transGroup = new TransactionGroup();
//loop through your transactions and populate the wrapper list
for(Transaction t : transactions){
//create a new transaction group if the date has changed
if(!currDate.isEqual(t.getDate()){
//fill the wrapper list before creating a new list
transGroup.setDate(currDate);
transGroup.setTransactions(transOnSingleDate);
transactionByDate.add(transGroup);
//create new TransactionGroup and List<Transaction> for a new date
transGroup = new TransactionGroup();
transOnSingleDate = new ArrayList<>();
}
transOnSingleDay.add( t );
currDate = t.getDate();
}
//add the final list
transGroup.setDate(currDate);
transGroup.setTransactions(transOnSingleDate);
transactionByDate.add(transGroup);
model.addAtrribute("transactionGroup", transactionByDate);
Hope this helps.
UPDATE:
The controller part is now ok. The List<TransactionGroup> object contains 3 transaction groups, one for each date. The thymeleaf template is wrong. It should be something like
<div th:each="singleGroup : ${transactionGroup}">
<div th:each="singleTrans : ${singleGroup.transactions}">
<h2>Amount: <span th:text="${singleTrans.amount}"></span></h2><br>
<h2>Note: <span th:text="${singleTrans.note}"></span></h2><br>
<h2>Wallet name: <span th:text="${singleTrans.walletName}"></span></h2><br>
<h2>Expense Category: <span th:text="${singleTrans.expenseCategories}"></span></h2><br>
<h2>IncomeCategory: <span th:text="${singleTrans.incomeCategories}"></span></h2>
<h2>IncomeCategory: <span th:text="${singleTrans.date}"></span></h2>
<div>
</div>
I think you don't need TransactionGroup as a intermediate class, just store transaction by Transaction entity, and you can get query by userId and return list of transactions, and from this list you can get all distinct dates,
If the specific user want to see all transactions in specific date you can define a query by two parameters with userId and Date from transaction repository.
So it can be better define a method with userId and Date(can be nullable) and return list of transactions.
Related
I'm curious to find a solution for this but couldn't find anything relatable and useful so far.
I have a table Transaction:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "transaction_id")
private Long id;
#Column(name = "user_id", nullable = false)
private Long userId;
#Column(name = "wallet_name", nullable = false)
private String walletName;
#NotNull(message = "Please, insert a amount")
#Min(value = 0, message = "Please, insert a positive amount")
private Double amount;
private String note;
#DateTimeFormat(pattern = "yyyy-MM-dd")
#Column(name = "date")
private LocalDate date;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "wallet_id", nullable = false)
private Wallet wallet;
#Enumerated(EnumType.STRING)
#Column(name = "transaction_type", columnDefinition = "ENUM('EXPENSE', 'INCOME')")
private TransactionType transactionType;
#Nullable
#Enumerated(EnumType.STRING)
#Column(name = "expense_categories", columnDefinition = "ENUM('FOOD_AND_DRINK', 'SHOPPING', 'TRANSPORT', 'HOME'," +
" 'BILLS_AND_FEES', 'ENTERTAINMENT', 'CAR', 'TRAVEL', 'FAMILY_AND_PERSONAL', 'HEALTHCARE'," +
" 'EDUCATION', 'GROCERIES', 'GIFTS', 'BEAUTY', 'WORK', 'SPORTS_AND_HOBBIES', 'OTHER')")
private ExpenseCategories expenseCategories;
#Nullable
#Enumerated(EnumType.STRING)
#Column(name = "income_categories", columnDefinition = "ENUM('SALARY', 'BUSINESS', 'GIFTS', 'EXTRA_INCOME', 'LOAN', 'PARENTAL_LEAVE', 'INSURANCE_PAYOUT', 'OTHER')")
private IncomeCategories incomeCategories;
Now, to display that data on Thymeleaf I created controller with model that I'm passing on Thymeleaf .
And that looks like this:
#GetMapping("/userTransactions/{user_id}")
public String getUserTransactions(#PathVariable("user_id") long user_id, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
long userId = user.getId();
model.addAttribute("userId", userId);
model.addAttribute("transactions", transactionService.findDistinctIdByUserId(user_id));
return "transactions";
}
As you can see, Transaction is connected with User so user actually can create a Transaction, and on that controller I'm just getting all transaction from each User and this is how I display it on Thymeleaf:
<div th:each="transactions : ${transactions}">
<h2>Amount: <span th:text="${transactions.amount}"></span></h2>
<br>
<h2>Note: <span th:text="${transactions.note}"></span></h2>
<br>
<h2>Date: <span th:text="${transactions.date}"></span></h2>
<br>
<h2>Wallet name: <span th:text="${transactions.walletName}"></span></h2>
<br>
<h2>Expense Category: <span th:text="${transactions.expenseCategories}"></span></h2>
<br>
<h2>IncomeCategory: <span th:text="${transactions.incomeCategories}"></span></h2>
</div>
Don't mind the way I formatted it, point is that works fine so far, I got all data displayed on page but I want to achieve one thing:
As you can see, while creating transaction user also pick a date, and what I want?
Lets say user have two transactions for today, I mean 18/01/2023
I want to have a heading for example like <div and to pass today date and each transaction from today, and below down for example 15/01/2023 because user also have a transactions on that date.
This is an example, as you can see I have today section because user made a transaction on today date, also for yesterday and then back on January 14, so I want to separate transactions for each that like that.
Example
Sorry for SS, I tried to add code snippet but cant find option on this updated SO.
I don't know from where to start, I found some options like to sort from ascending and descending order date but I want to avoid something like that and to give my best to achieve this. So any resource, tutorial or any help here will be fine. Thanks.
If you want to break it up by date, you should do that in the Java beforehand. Instead of passing a List<Transaction>, you should pass a List<TransactionGroup> where a TransactionGroup contains all the transactions for a day. It might look something like:
class TransactionGroup {
private LocalDate date;
private List<Transaction> transactions;
/* Getters and setters */
}
Then your html becomes simple.
<div th:each="group : ${transactionGroup}">
<h1 th:text="${group.date}" />
<div th:each="transaction : ${group.transactions}">
<h2>Amount: <span th:text="${transactions.amount}"></span></h2><br>
<h2>Note: <span th:text="${transactions.note}"></span></h2><br>
<h2>Wallet name: <span th:text="${transactions.walletName}"></span></h2><br>
<h2>Expense Category: <span th:text="${transactions.expenseCategories}"></span></h2><br>
<h2>IncomeCategory: <span th:text="${transactions.incomeCategories}"></span></h2>
<div>
</div>
I have a simple select using sqlQuery and I am trying to map it to an entity. I do not understand what the problem is or what can I do about it and I tried multiple sources from this site without any result
function that takes the records
public List<MYTABLE> getRecords(int first, int pageSize, String sortField, Map<String, Object> filters) throws DBEDatabaseException {
try {
EntityManager em = getMyEmOrThrow();
SQLQuery q = em.unwrap(SessionImpl.class).createSQLQuery("SELECT * FROM MYTABLE A where A.status = '1000'");
q.addEntity("A", MYTABLE.class);
q.setFirstResult(first);
q.setMaxResults(pageSize);
List<MYTABLE> results = q.list();
return results;
}catch(RuntimeException e){
throw new MyCustomException("Failure in getting records from table MYTABLE : ", e);
}
```
Entity - **getters and setters and rest of the columns omitted**
#Entity(name = "MYTABLE")
#Table(schema = "MYSCHEMA", name = "MYTABLE")
public class MYTABLE implements Serializable{
#Column(name = "TIMESTAMP", columnDefinition = "TIMESTAMP (6)") // this column is the problem
private Timestamp timestamp;
}
```
THIS DOESN'T WORK AS WELL
#Column(name = "TIMESTAMP", columnDefinition = "TIMESTAMP (6)")
#Temporal(TemporalType.TIMESTAMP)
private Date timestamp;
[Records in db look like this][1]
[1]: https://i.stack.imgur.com/ahDmJ.png
for formatting date output you should use SimpleDateFormat,
also you could define formatter method to your entity
I have a entity like this
#Entity
#Table(name = "PAYMENT")
public class PaymentSummary {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "payment_id", nullable = false, unique = true)
private Long id;
#Column(name = "date_created", nullable = false)
private LocalDateTime createdDate;
#OneToOne
#JoinColumn(name = "webOrder_id")
private WebOrder webOrder;
#Enumerated(EnumType.STRING)
#Column(name = "payment_type")
private PaymentType paymentType;
#Column(name = "amount")
private Double amount;
#Column(name = "username")
private String username;
}
and i have repository for this entity
#Repository
public interface PaymentRepository extends JpaRepository<PaymentSummary, Long> {
List<PaymentSummary> findAllByCreatedDate(LocalDateTime localDate);
}
Later i want to retrieve every payment was created in today
List<PaymentSummary> payments = paymentRepository.findAllByCreatedDate(LocalDateTime.now());
And it return null, i know because i pass LocalDateTime.now(), so it will find exact by Date-minus-second . I want to list all today payment , and still want to keep LocalDateTime createdDate, how can i handle this situation , do i need to write native query , or JPA support this ?
Thank you.
If you only need to store the date of the payment (year, month, day in month), and don't need time information (hour, minutes,...), you need to change LocalDateTime for LocalDate on your entity.
This way, you would have:
List<PaymentSummary> findAllByCreatedDate(LocalDate localDate);
And, using:
List<PaymentSummary> payments = paymentRepository.findAllByCreatedDate(LocalDate.now());
Would work.
If you need to store the date, and also the time information, you would need to use something like this:
List<PaymentSummary> findAllByCreatedDateBetween(LocalDateTime startDateTime, LocalDateTime endDateTime);
And call it with something like:
// 2020-04-12T00:00.000
LocalDateTime startDateTime = LocalDateTime.of(LocalDate.now() , LocalTime.MIN);
// 2020-04-12T23:59.999
LocalDateTime endDateTime = LocalDateTime.of(LocalDate.now() , LocalTime.MAX);
List<PaymentSummary> payments = paymentRepository.findAllByCreatedDateBetween(startDateTime, endDateTime);
It will return null because LocalDateTime.now() will create the current date and time. In your case I think you need to return by date only
I have 2 Entity classes the "Menu" which only has one field called "name" and second Entity - "Ingredients" which has 2 fields - "ingredientName" and "ingredientDescription". Database Structure
I'm creating a simple CRUD web-app , but the update method instead of updating the Entity , it inserts new values in the DB. I checked and when user clicks on the update on specified menu, the first entity's id and its ingredients id's as well are predifined. Im new to spring boot and thymeleaf and Don't really know how to work with JPA when you have more than 1 entity.
Menu entity :
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private String id;
#Column(name = "name")
private String name;
// Mapping To second table
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinTable(name = "menu_ingredient",
joinColumns = #JoinColumn(name = "menu_id"),
inverseJoinColumns = #JoinColumn(name = "ingredient_id"))
private List<Ingredients> ingredient = new ArrayList<>();
//Getters/Setters/Constructors/ToString
Ingredients entity :
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "ingredient")
private String ingredientName;
#Column(name = "description")
private String ingredientDescription;
//Getters/Setters/Constructors/ToString
Controller(Only the update methods) :
#GetMapping("/edit/{id}")
public String edit(#PathVariable(name = "id")String id, Model model){
Optional<Menu> menu = menuRepository.findById(id);
List<Ingredients> ingredients = menu.get().getIngredient();
for (Ingredients ing : ingredients){
System.out.println(ing);
}
model.addAttribute("ingredients", ingredients);
model.addAttribute("newMenu",menu);
return "edit-page";
}
#PostMapping("/postEditMenu")
public String postEdit(#ModelAttribute("newMenu")Menu menu){
menuRepository.save(menu);
return "redirect:/recipeList";
}
edit-page.html :
<form action = "#" th:action="#{/postEditMenu}" th:object="${newMenu}" method="post">
<p>Menu Name: <br><input type="text" th:field="*{name}"></p>
<div id="wrapper" th:each="ing: ${ingredients}">
<label for="ingredientName"></label>
<p>Ingredient Name: <br><input th:value="${ing.ingredientName}" id="ingredientName" type="text" name="ingName"></p>
<label for="ingredientDescription"></label>
<p>Ingredient Description:</p> <textarea id="ingredientDescription" type="text" th:text="${ing.ingredientDescription}" name="ingDesc"></textarea>
</div>
<br>
<input type="button" id="more_fields" onclick="add_fields();" value="Add More" />
<br>
<input type="submit" th:value="Submit">
</form>
FIX I actually figured it out with the help of below answers. Here's the code :
#PostMapping("/postEditMenu")
public String postEdit(#ModelAttribute("newMenu")Menu menu,
#RequestParam String ingName,
#RequestParam String ingDesc){
String[] ingNameSplit = ingName.split(",");
String[] ingDescSplit = ingDesc.split(",");
Menu menuToUpdate = menuRepository.getOne(menu.getId());
List<Ingredients> newIngredientList = menuToUpdate.getIngredient();
newIngredientList.clear();
for(int a = 0, b = 0; a<ingNameSplit.length; b++, a++){
newIngredientList.add(new Ingredients(ingNameSplit[a], ingDescSplit[b]));
}
menuToUpdate.setIngredient(newIngredientList);
menuRepository.save(menuToUpdate);
return "redirect:/recipeList";
}
So, First I added hidden "id" fields to each of the items required , like this :
<input type="text" th:field = "*{id}" hidden>
and
<input type="text" th:value = "${ing.id}" hidden>
Then, in the postEditMenu method, I added #RequestParam String ingName, and #RequestParam String ingDesc to get the input of new items from thymeleaf, then I split that String and add it to String[] array with String[] ingNameSplit = ingName.split(",") Because the input would be one big comma separated String and not array[] . Then I get the menu which user wants to update - Menu menuToUpdate = menuRepository.getOne(menu.getId()); The menu.getId() isn't null because I set hidden "id" fields in thymeleaf. Then I get the Ingredients of this menu - List<Ingredients> newIngredientList = menuToUpdate.getIngredient(); because the list would already be filled with existed ingredients I clear that list and add new ingredients which user will fill the form with -
for(int a = 0, b = 0; a<ingNameSplit.length; b++, a++){
newIngredientList.add(new Ingredients(ingNameSplit[a], ingDescSplit[b]));
}
after that I set this newIngredientsList and save the menu itself to the db -
menuToUpdate.setIngredient(newIngredientList);
menuRepository.save(menuToUpdate);
Thanks for all the help guys :)
At this point:
#PostMapping("/postEditMenu")
public String postEdit(#ModelAttribute("newMenu")Menu menu){
menuRepository.save(menu);
return "redirect:/recipeList";
}
You receive menu from edit-page.html and it has no id, that is why it always creates new records in database.
To edit the desired menu, you would need to have it's id before.
You can create endpoint for obtaining list of menus and display them with edit button next to each menu in html site. Then if user clicks edit button redirect him to your edit form, but this time you can pass menu's id.
First you need to fetch Menu entity from database by id using getOne and then you can update it.
Edit your code in postEdit method as follows:
Fetch Menu entity:
Menu menuToUpdate = menuRepository.getOne(menu.getId());
Update attributes:
menuToUpdate.setName(menu.getName());
Save entity:
menuRepository.save(menuToUpdate);
Add a hidden id field to hold the menu's id, and add hidden id fields for each ingredient.
I am working on an application where I have to display data/information about the vehicle details. I have 2 tables make and model with make_id being the foreign key in model table. I have 2 entity classes Make and Model as shown below:
#Entity
#Table(name = "make")
#PrimaryKeyJoinColumn(name="make_id")
public class Make {
#Id
#Column(name = "make_id")
private String makeId;
#Column(name = "make_name")
private String makeName;
#ManyToOne
#JoinColumn(name = "mfg_unit_id")
private MfgUnit mfgUnit;
// Getter and Setters
}
#Entity
#Table(name = "model")
public class Model {
#Id
#Column(name = "model_id")
private String modelId;
#Column(name = "model_creation_date")
private Date modelCreationDate;
#Column(name = "make_id")
private long makeId;
#ManyToOne
#JoinColumn(name = "make_id")
private Make make;
// Getter and Setters
}
I am able to retrieve all the Makes, but my requirement is to only retrieve the Makes for which the model_creation_date is between today and last 30 days. Can anyone help me with how to build the Hibernate criteria for this?
there can be another solution, but to achieve this you need to modify your Make class as following introducing a new relationship (#OneToMany) with Model class:
#Entity
#Table(name = "make")
#PrimaryKeyJoinColumn(name="make_id")
public class Make {
#Id
#Column(name = "make_id")
private String makeId;
#Column(name = "make_name")
private String makeName;
// ** introduced new relationship **
#OneToMany(mappedBy="make", fetch = FetchType.LAZY)
private List<Model> models;
#ManyToOne
#JoinColumn(name = "mfg_unit_id")
private MfgUnit mfgUnit;
// Getter and Setters
}
And keep the 'Model' class as it is:
#Entity
#Table(name = "model")
public class Model {
#Id
#Column(name = "model_id")
private String modelId;
// change the datatype as Date or similar Datatype
#Column(name = "model_creation_date")
private Date modelCreationDate;
#Column(name = "make_id")
private long makeId;
#ManyToOne
#JoinColumn(name = "make_id")
private Make make;
// Getter and Setters
}
Once you have the relationship with 'Model' from 'Make' you can execute the following code to get your result:
Calendar cal = Calendar.getInstance();
// today
Date toDate=cal.getTime();
cal.add( Calendar.DATE, -30 );
//date before 30 days
Date fromDate=cal.getTime();
Criteria criteria = session.createCriteria(Make.class , "m")
.createAlias("models", "s")
.add(Restrictions.between("s.modelCreationDate", fromDate, toDate))
// if the above condition dosen't give you exact result you may try following(2)
// try gt or lt ... as needed
//.add(Restrictions.ge("publicationDate", fromDate))
//.add(Restrictions.le("publicationDate", fromDate))
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
List<Make> ll2 = criteria.list();
Sorry I have no idea why did you declare date as String:
private String modelCreationDate;
Anyway, I assume you will declare modelCreationDate as Date/LocalDate or with similar Type. I haven't tested the code but I hope the following code will resolve your issue. Good luck!
Calendar cal = Calendar.getInstance();
// today
Date toDate=cal.getTime();
cal.add( Calendar.DATE, -30 );
//date before 30 days
Date fromDate=cal.getTime();
Criteria criteria = session.createCriteria(Model.class , "s")
.createAlias("make", "m")
.add(Restrictions.between("s.modelCreationDate", fromDate, toDate))
// if the above condition dosen't give you exact result you may try following(2)
// try gt or lt ... as needed
//.add(Restrictions.ge("publicationDate", fromDate))
//.add(Restrictions.le("publicationDate", fromDate))
.setProjection(
Projections.projectionList()
.add(Projections.groupProperty("m.makeId").as("makeId"))
.add(Projections.property("m.makeName").as("makeName"))
)
.setResultTransformer(Transformers.aliasToBean(Make.class));
List<Make> ll2 = criteria.list();
Alternative to user3169715's answer, I could also retrieve the records using a query
Calendar cal = Calendar.getInstance();
Date toDate = cal.getTime();
cal.add(Calendar.DATE, -30);
Date fromDate = cal.getTime();
String hql = "SELECT make FROM Model m where m.modelCreationDate between :from_date and :to_date";
Query query = session.createQuery(hql);
query.setParameter("from_date", fromDate);
query.setParameter("to_date", toDate);
List results = query.list(); // Result list