Hibernate Update not working...using Spring framework - java

POJO:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#Column(name = "name")
private String name;
#Generated(GenerationTime.INSERT)
#Basic(optional = false)
#Column(name = "created_at")
#Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
#Generated(GenerationTime.ALWAYS)
#Basic(optional = false)
#Column(name = "updated_at")
#Temporal(TemporalType.TIMESTAMP)
private Date updatedAt;
Controller:
#Controller
#RequestMapping(value = "/")
public class HomeController {
#Autowired
private NameDao nDao;
#RequestMapping(value="/update/{id}", method=RequestMethod.GET)
public String getUpdate(#PathVariable int id, Model model){
Stamp st = (Stamp) nDao.getById(id);
model.addAttribute("s", st);
return "update";
}
#RequestMapping(value="/update/{id}", method=RequestMethod.POST)
public String postUpdate(#ModelAttribute Stamp s){
nDao.updateName(s);
return "redirect:/";
}
Update.jsp:
<h1>Update Here...</h1>
<form method = "post">
<div>
<label>Name: </label><input type="text" value="${s.name}" name="name">
</div>
<input type="submit" value="Submit">
</form>
My only concern is using the createdAt and updatedAt for each entry. On using createdAt and updatedAt dateTime, the problem of updating arose. Update now working. Any solution to use dateTime for createdAt and updatedAt working with upadate operation. Insert option works fine here.

Use #CreationTimestamp and #UpdateTimestamp instead of manually setting those values

Related

Data from entity are not showing on page from Thymeleaf

I have this table:
#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;
Because, I want to display transactions by date on page I created a separated class like this:
public class TransactionGroup {
private LocalDate date;
private List<Transaction> transactions;
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public List<Transaction> getTransactions() {
return transactions;
}
public void setTransactions(List<Transaction> transactions) {
this.transactions = transactions;
}
public void setTransactions(String walletName, Double amount, String note, LocalDate date, TransactionType transactionType, ExpenseCategories expenseCategories, IncomeCategories incomeCategories) {
}
}
So, as you can see I have a list of transactions. In my controller where I'm saving transaction I have this:
#PostMapping("/saveIncome/{walletId}")
public String saveIncome(#PathVariable(value = "walletId") long walletId, #Valid Transaction transaction, BindingResult result, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
long userId = user.getId();
Wallet wallet = walletService.getWalletById(walletId);
TransactionGroup transactionGroup = new TransactionGroup();
boolean thereAreErrors = result.hasErrors();
if (thereAreErrors) {
model.addAttribute("incomeCategories", IncomeCategories.values());
return "income_transaction";
}
transaction.setWallet(wallet);
transaction.setUserId(userId);
transaction.setWalletName(wallet.getWalletName());
transactionGroup.setTransactions(transaction.getWalletName(), transaction.getAmount(), transaction.getNote(), transaction.getDate(), transaction.getTransactionType(), transaction.getExpenseCategories(), transaction.getIncomeCategories());
transactionService.saveIncome(transaction, walletId, userId);
return "redirect:/api/wallet/userWallet/balance/" + userId;
}
This is the thing:
transactionGroup.setTransactions(transaction.getWalletName(), transaction.getAmount(), transaction.getNote(), transaction.getDate(), transaction.getTransactionType(), transaction.getExpenseCategories(), transaction.getIncomeCategories());
And that works fine, transaction is saved. Now when I want to show data from that entity like this:
<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>
</div>
</div>
I'm getting a blank page without any transaction data.
I already asked a question similar to this, you can see it from my profile. Idk what to try more and why data is not displayed so far.

how to add user to team to admin page

I can’t understand how to implement adding a user to Team on the admin page.
I wrote the add method in the controller, I can’t understand how to show it all in the interface.
Need two lists, one list of all Teams and a second list of all users and then save?
began to learn thymeleaf and a lot of strange things.
admin.html
</head>
<body>
<h1>Admin page </h1>
<!--
<form action="#" th:action="#{/admin}" th:object="${team}" method="post">
<p>Add Team: <input type="text" th:field="*{name}" /></p>
<p><input type="submit" value="addTeam" />
</form>
-->
<form th:action="#{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
Users
#Entity
#Table(name="users")
public class Users {
#Id
#Column(name="email",unique = true, nullable = false,length = 200)
String email;
#Column(name="name",nullable = false,length = 200)
String name;
#Column(name="password",nullable = false,length = 128)
#JsonIgnore
String password;
#Column(name = "avatar", nullable = true)
String avatar;
#ManyToOne
#JoinColumn(name="team_id", nullable=true)
Team team;
#ManyToOne
#JoinColumn(name="role", nullable=false)
#JsonIgnore
Role role;
public Users() {
}
get und set
}
Team
Entity
#Table(name="team")
public class Team {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#Column
String name;
#Column
String url;
#Lob
#Column(name = "avatar",nullable = true,columnDefinition="BLOB")
String avatar;
#OneToMany(mappedBy="team",cascade = CascadeType.ALL, orphanRemoval = true)
#JsonIgnore
Set<Users> users = new HashSet<>();
public Team() {
}
get und set
AdminController
#Controller//RestController
public class AdminController {
.....
#GetMapping("/admin/team")
List<Team> allTeams() {
return teamRepository.findAll();
}
#RequestMapping(value = "/admin/team/{id}/user/{email}", method = RequestMethod.POST,produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
public Users addUserToTeam(
#PathVariable long id,#PathVariable String email) {
Team team = teamRepository.findById(id).orElseThrow(() -> new NoSuchTeamException("Team not found"));
Users user = userRpRepository.findById(email).orElseThrow(() -> new NoSuchUserException("User not found"));
user.setTeam(team);
user = userRpRepository.save(user);
return user;
#RequestMapping(value = "/admin", method = RequestMethod.GET)
public String adminPage(Model model) {
model.addAttribute("admin",new Team());
return "admin";
}
}
Ideologically from RMDB structure, the better way is creating the linkage table between User and Team.
User
#Entity
#Table(name = "user")
public class User {
#Id
#Column(name = "email", length = 200) //#Id controls nullable and unique
private String email;
#Column(name = "name", nullable = false, length = 200)
private String name;
#Column(name = "password", nullable = false, length = 128)
#JsonIgnore
private String password;
#Column(name = "avatar", nullable = true)
private String avatar;
#ManyToMany(cascade = CascadeType.ALL) //by default fetch - LAZY
#JoinTable(name = "user_team", joinColumn = #JoinColumn(name = "user_id",
foreignKey = #ForeignKey(name = "fk_user_team__user"), nullable = false),
inverseJoinColumns = #JoinColumn(name = "team_id",
foreignKey = #ForeignKey(name = "fk_user_team_team"), nullable = false))
private Set<Team> teams;
}
Team
#Entity
#Table(name = "team")
public class Team {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String name;
#Column
private String url;
#Lob
#Column(name = "avatar", nullable = true, columnDefinition = "BLOB")
private String avatar;
#ManyToMany(cascade = CascadeType.ALL) //by default fetch - LAZY
#JoinTable(name = "user_team", joinColumn = #JoinColumn(name = "team_id",
foreignKey = #ForeignKey(name = "fk_user_team__team"), nullable = false),
inverseJoinColumns = #JoinColumn(name = "user_id",
foreignKey = #ForeignKey(name = "fk_user_team_user"), nullable = false))
private Set<User> users;
}
UserTeam
#Entity
#Table(name = "user_team", uniqueConstraints =
#UniqueConstraints(columnNames = {"user_id", "team_id"}, name = "uniq_some")
public class UserTeam {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; //it's easier to create new Long Id key then composite key with user_id and team_id
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id", foreignKey = #ForeignKey(name = "fk_user_team__user"), nullable = false)
private User user;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "team_id", foreignKey = #ForeignKey(name = "fk_user_team__team"), nullable = false)
private Team team;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "role_id", nullable = false) //I don't see Role entity but think it has id field
#JsonIgnore
private Role role;
}
With this structure, you can get all users for the Team and all teams for the User. Collections are lazy so you need to use #Transactional, for example, for appropriate service methods.
And this structure is bi-directional: if you add new User into users collection in Team object, JPA will create new User. But ... linkage table contains one more required field role_id, so on such addition you will get an exception. So better first create User and Team objects, and after that create UserTeam linkage object with required Role (or set default Role and all new objects will be created with this Role).

Spring Boot findById is not working but findAllById works fine

I have an Bid entity defined as follows
#ToString
#NoArgsConstructor
#AllArgsConstructor
#Setter
#Getter
#Entity
#Table(name = "bid_details")
public class Bid {
private enum STATUS { INITIATED, DRAFT, COMPLETED }
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false, updatable = false)
private Integer id;
#Column(name = "govt_bid_id", nullable = false)
private String govtBidNumber;
#Temporal(TemporalType.DATE)
#Column(name = "release_date", nullable = false)
#JsonFormat(pattern = "dd-MM-yyyy")
private Date releaseDate;
#ManyToOne(optional = false)
#JoinColumn(name = "created_by", referencedColumnName = "id", updatable = false, nullable = false)
private User createdBy;
#Temporal(TemporalType.DATE)
#Column(name = "created_date", nullable = false)
#CreationTimestamp
private Date createdDate;
#ManyToOne
#JoinColumn(name = "updated_by", referencedColumnName = "id", updatable = false, nullable = false)
private User updatedBy;
#Enumerated(EnumType.STRING)
#Column(name = "status", nullable = false)
private STATUS status;
#Column(name = "avg_turnover")
private String avgTurnover;
#Convert(converter = StringListConverter.class)
#Column(name = "docs_required", columnDefinition = "json")
private List<String> docsRequired;
#Enumerated(EnumType.STRING)
#Column(name = "status", nullable = false)
private STATUS status;
}
and the corresponding columns are present in the bid_details tables. I have bid repository defined as follows:
public interface BidRepository extends JpaRepository<Bid, Integer> {
}
now when I try to access data by id using findById it is throwing No Value Present exception whereas if I try to access the data using findAllById I am getting correct result. Not able to figure out what's causing this weird behaviour.
Also, if I execute findAll first and then findById it is giving the correct result.
I am using spring-boot version 2.1.1
following is code where the entity is saved in the db
public Bid addBid(BidRequest bidRequest) {
User user = userRepository.findById(bidRequest.getCreatedBy()).get();
Bid bid = new Bid();
modelMapper.map(bidRequest, bid);
bid.setCreatedBy(user);
return bidRepository.save(bid);
}
BidRequest class is as follows:
#ToString
#NoArgsConstructor
#AllArgsConstructor
#Setter
#Getter
public class BidRequest {
private String govtBidNumber;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "yyyy-MM-dd")
private Date releaseDate;
#Temporal(TemporalType.DATE)
private Date endDate;
private int createdBy;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "yyyy-MM-dd")
private Date createdDate;
private int updatedBy;
private String status;
private List<String> docsRequired;
}
Have you tried orElse like this
findById(id).orElse(null);
Because findById returns an Optional object so you have to write orElse() after findById()

How to show related objects in a jstl using a spring?

I have 3 objects: User, Comment and StatusUpdate(news). This is the User...
#Entity
#Table(name = "users")
#PasswordMatch(message = "{register.repeatpassword.mismatch}")
public class SiteUser {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "email", unique = true)
#Email(message = "{register.email.invalid}")
#NotBlank(message = "{register.email.invalid}")
private String email;
#Transient
#Size(min = 5, max = 15, message = "{register.password.size}")
private String plainPassword;
#Column(name = "password", length = 60)
private String password;
#Column(name = "enabled")
private Boolean enabled = false;
#NotNull
#Column(name = "firstname", length = 20)
#Size(min = 2, max = 20, message = "{register.firstname.size}")
private String firstname;
#NotNull
#Column(name = "surname", length = 25)
#Size(min = 2, max = 25, message = "{register.surname.size}")
private String surname;
#Transient
private String repeatPassword;
#Column(name = "role", length = 20)
private String role;
public SiteUser() {
}
Here comes the StatusUpdate(you can call it piece of news or article). That has a site user that is the one who has created that article.
#Entity
#Table(name = "status_update")
public class StatusUpdate {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Size(min=5, max=255, message="{addstatus.title.size}")
#Column(name = "title")
private String title;
#Size(min=5, max=5000, message="{addstatus.text.size}")
#Column(name = "text")
private String text;
#Column(name = "added")
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern="yyyy/MM/dd hh:mm:ss")
private Date added;
#OneToOne(targetEntity = SiteUser.class)
#JoinColumn(name="user_id")
private SiteUser siteUser;
#PrePersist
protected void onCreate() {
if (added == null) {
added = new Date();
}
}
public StatusUpdate() {
}
And the Comment which can be done by any registered user, right? As you will notice the Comment has no User object to avoid circular references.
#Entity
#Table(name = "comments")
public class Comment {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name = "statusupdateid")
private StatusUpdate statusUpdate;
#Column(name = "commenttext")
private String commenttext;
#Column(name = "commentdate")
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern = "yyyy/MM/dd hh:mm:ss")
private Date commentdate;
#Column(name = "userid")
private Long userid;
public Comment() {
}
Now I would like to show in my JSP an article, with all the related comments and each of them belong to a different user. Can I use a HashMap to relate the users and their comments? I do not see how.
#RequestMapping(value ="/viewonestatus/{id}")
public ModelAndView viewOneStatus(#PathVariable("id") Long id) {
StatusUpdate status = statusUpdateService.get(id);
int countComments = commentService.countStatusComments(status);
List<Comment> comments = commentService.readAllComments(status);
ModelAndView modelAndView = new ModelAndView();
for (Comment comment: comments){
SiteUser user = userService.get(comment.getUserid());
modelAndView.getModel().put("user", user);
}
modelAndView.getModel().put("commentscounter", countComments);
modelAndView.getModel().put("status", status);
modelAndView.getModel().put("comments", comments); //!!
modelAndView.setViewName("app.viewonestatus");
return modelAndView;
}
As you expect, when my JSP shows just one user (the last one) for all the comments, but I can not relate all the Comments with the corresponding Users
<table class="table table-hover">
<c:forEach var="comment" items="${comments}">
<tr>
<td>
<div class="col-sm-2 sm-margin-bottom-40">
<img class="img-responsive profile-img margin-bottom-20" id="profilePhotoImage" src="/profilephoto/${comment.userid}" />
</div>
<h4>
${user.firstname} ${user.surname}
<span>
<!-- <span>${counterUserMap[comment.key]}</span> -->
5 hours ago / Reply
</span>
</h4>
<p>
<fmt:formatDate pattern="EEEE d MMMM y 'at' H:mm:ss" value="${comment.commentdate}" />
</p>
<p>${comment.commenttext}</p>
</td>
</tr>
</c:forEach>
I do not want to use JSON. I'm thinking about an anonymous class with all the stuff inside. Well, I'm open to your thoughts. Thanks.
Shokulei answer was the solution:
Since you have the userid, you can link it using the #ManyToOne annotation. This would be the most ideal way. But if you really don't want to link them, then you can create a new #Transient SiteUser siteUser; attribute in Comment class. And then in your for loop, you can use comment.setSiteUser(user); instead of modelAndView.getModel().put("user", user);. Hope this will help.
Thanks Shokulei

Is it possible to instruct hibernate not to set null values while performing insert?

I have the entity:
#Entity
#Table(name = "message")
public class Message {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "email")
private String email;
#Column(name = "subject")
private String subject;
#Column(name = "content")
private String content;
#Column(name = "html")
private String html;
#Column(name = "status")
private Integer status;
#Column(name = "creation_date")
private Date creationDate;
#Column(name = "send_date")
private Date sendDate;
//GET, SET
}
The table message has the following definition for the column creation_date:
creation_date timestamp without time zone NOT NULL DEFAULT now()\
As a conslusion, when I don't set a specific value to creation_date, hibernate will generate a query which looks like as follows:
insert into partner.message (content, creation_date, email, html, send_date, status, subject)
values ('text', null, 'text', 'text', null, '1', 'text')
Is it possible to avoid generating those null-values?
BTW, I'm on PostgreSQL. Does it have something to do with PostgreSQL-dialect?
You should set your column creationDate as non nullable:
#Column(name = "creation_date", nullable = false)
private Date creationDate;
IIRC, Hibernate should throw an exception when doing an insert if it is null. This way you have to make sure it is always set.
Another option is to have a default value for creationDate:
#Column(name = "creation_date", nullable = false)
private Date creationDate = new Date(); //Or set it in the constructor

Categories

Resources