Hibernate not saving some properties - java

I'm working on a project using Spring Data JPA and Hibernate and one of my entities has a pretty weird behaviour: it's not saving some of the properties. The code below is my model class. It has some more properties and but all of them are String with the columnDefinition="TEXT". Debugging the object I'm sending to the repository all properties have values in it, get and set methods are working fine, etc.. but it only saves the title.
Now comes the weird part, if I do this Column(name = "isbn_v", columnDefinition="TEXT") it saves the data normally. The same for all columns that are not saving. I don't understand why. Model class:
#Entity
#Table(name = "notice")
public class Notice implements Serializable {
private static final long serialVersionUID = 4521230269805147556L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "seq_no", nullable = false, updatable = false)
private Integer id;
#Column(name = "title", columnDefinition="TEXT")
private String title;
#Column(name = "isbn", columnDefinition="TEXT")
private String isbn;
#Column(name = "issn", columnDefinition="TEXT")
private String issn;
#Column(name = "author", columnDefinition="TEXT")
private String author;
#Column(name = "publisher", columnDefinition="TEXT")
private String publisher;
// get / set
}
Repository class:
public interface NoticeRepository extends JpaRepository<Notice, Integer>, JpaSpecificationExecutor<Notice> {
#Override
#Modifying
#Transactional
Notice save(Notice notice);
}
Any clue of what I'm doing wrong?

Related

How to properly encapsulate uncommon fields in JPA entity definition

I am working on a Java 8 project with an Oracle database. The project uses Spring Boot and JPA. Currently, the JPA Entity is defined in the following manner
#Entity
#Table(name = "TEST")
public class TestEntity {
#Column(name = "ID", columnDefinition = "NVARCHAR2(140)")
private String id;
#Column(name = "COMMON_FIELD_1", columnDefinition = "NVARCHAR2(60)")
private String commonField1;
#Column(name = "COMMON_FIELD_2", columnDefinition = "NVARCHAR2(60)")
private String commonField2;
#Column(name = "UNCOMMON_FIELD_1", columnDefinition = "NVARCHAR2(60)")
private String uncommonField1;
#Column(name = "UNCOMMON_FIELD_2", columnDefinition = "NVARCHAR2(60)")
private String uncommonField2;
}
Here - the fields id, commonField1, and commonField2 are present for every database entry and every instance of a TestEntity. The fields uncommonField1 and uncommonField2 will not be present in every database entry (null when not present) and will also not be present in every instance of TestEntity.
Although the code functionally does know which uncommon fields to expect in any given instance of TestEntity, it is bad practice to have those fields accessible across every instance of TestEntity. I would like to encapsulate these fields in such a way that only those fields which the code expects to be present are actually accessible.
Here is an example of what I would like to accomplish:
#Entity
#Table(name = "TEST")
public abstract class TestEntity {
#Column(name = "ID", columnDefinition = "NVARCHAR2(140)")
private String id;
#Column(name = "COMMON_FIELD_1", columnDefinition = "NVARCHAR2(60)")
private String commonField1;
#Column(name = "COMMON_FIELD_2", columnDefinition = "NVARCHAR2(60)")
private String commonField2;
}
public class TestEntityA extends TestEntity {
#Column(name = "UNCOMMON_FIELD_1", columnDefinition = "NVARCHAR2(60)")
private String uncommonField1;
}
public class TestEntityB extends TestEntity {
#Column(name = "UNCOMMON_FIELD_2", columnDefinition = "NVARCHAR2(60)")
private String uncommonField2;
}
Is it possible to implement something like what I've described above? Can my database table contain all 5 columns?

spring data jpa find all by example nested collection property

I have two objects. The company that can have multiple nested addresses.
#Entity
#Data
#Table(name = "company")
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "phone")
private String phone;
#OneToMany(mappedBy = "company", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<Address> addresses;
}
Address class looks like this:
#Data
#Entity
#Table(name = "address")
#ToString(exclude = "company")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "postal_code")
private String postalCode;
#Column(name = "city")
private String city;
#Column(name = "street")
private String street;
#JsonIgnore
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "company_id")
private Company company;
}
I want somehow if it's possible, make a dynamic query that searches through the nested collection property. I made a search method which uses example matcher but the result is wrong. Every time I got everything from DB, not only company with address postal code that I'm looking for.
My search method looks like this:
#PostMapping("/search")
public List<Company> search(#RequestBody final Company company){
return companyRepository.findAll(Example.of(company,
ExampleMatcher.matchingAny()
.withIgnoreNullValues()
.withIgnorePaths("id")
.withStringMatcher(ExampleMatcher.StringMatcher.STARTING)));
}
In my database, I have two objects and this is the result of the search:
As you can see I received everything from DB instead of the only first company which address postal code starts with 1.
Hi you can use Specification<T>
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
For this you need to extend from interface JpaSpecificationExecutor:
public interface UserRepository extends JpaRepository<User> ,JpaSpecificationExecutor<User>{
}
And you also need to implement your custom Specification<T>
And then you can use repository.findAll(your impleneted Specification);
Spring docs :
https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaSpecificationExecutor.html
I think this is helpful.

Mapping a database view entity with a simple entity and pass to DTO using Spring Data

I'm just learning Spring Data. I want to map a database view Entity with a simple Entity and pass to DTO which will contain columns both entities. I understand that I can use a special database view but I need to map precisely entities of Spring Data.
I have a database view Entity "MentorStudents":
#Entity
#Table(name = "mentor_students")
#Immutable
public class MentorStudents implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "mentor_id", updatable = false, nullable = false)
private Long mentorId;
//This entity I need to map
private Mentor mentor;
#Column(name = "active_students")
private Integer activeStudents;
public MentorStudents() {
}
//getters, setters, equals, hashCode
}
A database view sql of an above entity is:
SELECT id AS mentor_id, active_students
FROM mentor
LEFT JOIN ( SELECT mentor_id, count(mentor_id) AS active_students
FROM contract
WHERE close_type IS NULL
GROUP BY mentor_id) active ON mentor.id = active.mentor_id
ORDER BY mentor.id;
And I have a simple Entity "Mentor":
#Entity
#Table(name = "mentor")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Mentor implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Column(name = "first_name", nullable = false)
private String firstName;
#NotNull
#Column(name = "last_name", nullable = false)
private String lastName;
#Column(name = "patronymic")
private String patronymic;
#Column(name = "phone")
private String phone;
#NotNull
#Column(name = "email", nullable = false)
private String email;
#Column(name = "skype")
private String skype;
#Column(name = "country")
private String country;
#Column(name = "city")
private String city;
#Column(name = "max_students")
private Long maxStudents;
//getters, setters, equals, hashCode
I have to get a DTO which contains all Mentor fields and an "activeStudents" MentorStudents field without a "mentorId" field. How do it?
Use spring data projection:
public interface YourDto {
// all Mentor get fields
String getFirstName();
...
// activeStudents get field
Integer getActiveStudents();
}
public interface YourRepository extends JpaRepository<YourEntity, Integer> {
#Query(value = "select ...(all fields match YourDto) from Mentor m, MentorStudents s where m.id = s.mentorId and m.id = ?1")
Optional<YourDto> findMyDto(Integer mentorId);
}

Spring Boot and Thymeleaf: Joined Entity Object Returning as null

I am using Spring Boot framework with Hibernate and JPA, and Thymeleaf for the view element. I want to show related data from 2 different entities on the same HTML table on a page. However the object which should contain the data from my joined entity is returning as null.
EDIT: The root cause of the problem is that the query which is being executed is joining my two tables on the 2 primary keys rather than on the primary key of my MsgOrig table and the foreign key of my ReplyMessage table ("msgOrigID") as intended. Any idea how I can correct this?
Also, just to get this working I am trying to return all messages. However my ultimate aim is to only return messages sent by the logged-in user. Is there a JPA repository method which could be used for this purpose? Or should I write a custom query instead?
Entity Class for MsgOrig:
#Entity
#Table(name = "messageoriginator")
public class MsgOrig {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column(name = "Date")
private String date;
#Column(name = "MsgTime")
private String msgTime;
#Column(name = "message")
private String msg;
#Column(name = "email")
private String email;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "msgOrigID")
private ReplyMessage reply;
//getters and setters
}
Entity Class for ReplyMessage:
#Entity
#Table(name = "replymessage")
public class ReplyMessage {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column(name = "msgOrigID")
private int msgOrigId;
#Column(name = "Date")
private String date;
#Column(name = "MsgTime")
private String msgTime;
#Column(name = "message")
private String msg;
#Column(name = "email")
private String email;
#OneToOne(mappedBy="reply")
private MsgOrig msgOrig;
//getters and setters
}
Controller Method:
#RequestMapping(value={"/mymessages"}, method = RequestMethod.GET)
public ModelAndView messages(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("mymessages", messageService.listAllMessages());
return modelAndView;
}
Implementation Class For MessageService interface:
#Service("messageService")
public class MessageServiceImpl implements MessageService{
#Autowired
private MessageRepository messageRepository;
#Override
public List<MsgOrig> listAllMessages() {
return messageRepository.findAll();
}
}
Repository class:
#Repository("messageRepository")
public interface MessageRepository extends JpaRepository<MsgOrig, Integer> {
#Query("SELECT t.email FROM MsgOrig t where t.id = :id")
String findUsersEmail(#Param("id") int id);
}
Relevant section on Thymeleaf template (returns "NOT FOUND"):
<td th:text="${mymessages.reply != null ? mymessages.reply.msgTime : 'NOT FOUND'}"/>

What is the simplest way to create nested objects in Ebean?

I need two Ebean model classes called "States" and "Children". A "State" object can contain nested Child objects(List of children).
Here is the basic States class,
#Entity
public class States extends Model {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Constraints.Required(message = "stateName cannot be null")
#Column(nullable = false)
private String statename;
#Column(nullable = true)
private String url;
#Column(nullable = true)
private String parent;
private List<Children> childrenList;
}
Here is the basic Children class,
#Entity
public class Children extends Model {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(nullable = false)
private String statename;
#Column
private String child;
}
What are the minimal modifications that should be done to these classes to create State objects using Ebean ORM? I went through the post,
Ebean Query by OneToMany Relationship
But there, a lot of changes have been suggested. I just want the minimal modifications.
All I had to do was, doing a small modification to the "States" class,
#Entity
public class States extends Model {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Constraints.Required(message = "stateName cannot be null")
#Column(nullable = false)
private String statename;
#Column(nullable = true)
private String url;
#Column(nullable = true)
private String parent;
#OneToMany(cascade = CascadeType.ALL)
private List<Children> childrenList;
}
Only change I have done here is,
#OneToMany(cascade = CascadeType.ALL)
I did not do any changes to the "Children" class. Before starting the play app I set
play.evolutions.enabled = true
in "application.conf" file. Then using the evolution SQL file that was created in "evolution.default" folder, I adjusted the schema of the database. After that "States" objects were created successfully with nested "Children" objects.

Categories

Resources