How to use an order by clause with an embedded field in the spring data jpa derived query? - spring

I have two entities : Article and Category
#AllArgsConstructor
#Entity
#ToString
#Table(name = "articles")
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "title", nullable = false, unique = true)
private String title;
#Embedded
private Audit audit = new Audit();
#ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
#JoinTable(name = "articles_categories", joinColumns = {#JoinColumn(name = "articles_id")}, inverseJoinColumns = {#JoinColumn(name = "categories_id")})
#JsonManagedReference
private List<Category> categories = new ArrayList<>();
Now the entity Category
Then I have Category entity
#Getter
#Setter
#Accessors ( chain = true )
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table ( name = "category" )
public class Category {
#Id
#GeneratedValue ( strategy = GenerationType.IDENTITY )
#Column ( name = "id" )
private Long id;
#Column ( name = "name", nullable = false, unique = true )
private String name;
#ManyToMany ( fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST , CascadeType.MERGE }, mappedBy = "categories" )
#JsonBackReference
private Set<Article> categories = new HashSet<>();
}
And now the entity Embedded
#Getter
#Setter
#Embeddable
#RequiredArgsConstructor
public class Audit {
#Column ( name = "created_on" )
private Date createdOn;
#Column ( name = "updated_on" )
private Date updatedOn;
#PrePersist
public void prePersist ( ) {
createdOn = new Date ( );
}
#PreUpdate
public void preUpdate ( ) {
updatedOn = new Date ( );
}
}
In my article repository I have the following JPA.
#Repository
public interface ArticleRepository extends JpaRepository < Article, Long > {
Page<Article> findByCategoriesIn (List<Category> categories, Pageable pageable);
}
This works correctly and is returning a page of articles but I would like to order articles by creation date using #Embeeded annotation.
How could I use this ?

Try to use something like this:
Page<Article> findByCategoriesInOrderByAudit_CreatedOnDesc(List<Category> categories, Pageable pageable);
See also this and this sections of the documentation.

Related

Add extra custom column to auto mapped Table in Spring JPA ManyToMany

#Getter #Setter #NoArgsConstructor #AllArgsConstructor
#Table(name = "my_users")
public class MyUsers {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(nullable = false)
private Long id;
#Column(nullable = false, unique = true)
private String userName;
private String password;
#ManyToMany
private List<MyUsers> connections;
}
This is my MyUsers Model Class. I am using Hibernate and MySQL.
#ManyToMany
private List<MyUsers> connections;
This ManyToMany relationship is automatically creating the table 'my_users_connections' with 'my_users_id' and 'connections_id' colums. How can I add extra columns to this auto mapped table?
It's not ideal solution...
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "my_users")
public class MyUsers implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(nullable = false)
private Long myUsersId;
#Column(nullable = false, unique = false)
private String userName;
private String password;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "my_users_connections",
joinColumns = { #JoinColumn(name = "my_users_id") },
inverseJoinColumns = { #JoinColumn(name = "connections_id") })
private List<MyUsers> connections;
}
Create embedded id MyUsersConnectionsPK:
#Data
#Embeddable
public class MyUsersConnectionsPK implements Serializable {
#Column(name = "my_users_id")
private Long myUsersId;
#Column(name = "connections_id")
private Long connectionsId;
}
Create MyUsersConnections, which represent ManyToMany
#Data
#Entity
#Table(name = "my_users_connections")
public class MyUsersConnections implements Serializable {
#EmbeddedId
private MyUsersConnectionsPK id;
#ManyToOne
#MapsId("my_users_id")
#JoinColumn(name = "my_users_id")
private MyUsers myUsersId;
#ManyToOne
#MapsId("connections_id")
#JoinColumn(name = "connections_id")
private MyUsers connectionsId;
#Column(name = "extra_column")
private String extraColumn;
}
Create JPA repository
#Repository
public interface MyUsersConnectionsRepository extends JpaRepository<MyUsersConnections, MyUsersConnectionsPK> {
List<MyUsersConnections> findMyUsersConnectionsByMyUsersIdMyUsersId(Long id);
}
And simple sample for using:
#Service
public class Test {
#Autowired
private MyUsersConnectionsRepository myUsersConnectionsRepository;
#Autowired
private MyUsersRepository myUsersRepository;
public void test() {
MyUsers myUsers = new MyUsers();
myUsers.setUserName("user name");
myUsers.setPassword("password");
MyUsers myUsers2 = new MyUsers();
myUsers2.setUserName("user name 2");
myUsers2.setPassword("password 2");
myUsers.setConnections(Collections.singletonList(myUsers2));
myUsers = myUsersRepository.saveAndFlush(myUsers);
List<MyUsersConnections> myUsersConnections = myUsersConnectionsRepository.findMyUsersConnectionsByMyUsersIdMyUsersId(myUsers.getMyUsersId());
MyUsersConnections item = myUsersConnections.get(0);
item.setExtraColumn("Extra column");
myUsersConnectionsRepository.saveAndFlush(item);
}
}

JPA, Simple One-To-Many Relationship Fetching Problem

Simple Fetch Problem I'm facing in a straight-forward OneToMany Relationship: One Author Many Books.
Here's Author :
#Entity
#Table(name = "authors")
public class AuthorEntity {
#Id
#GeneratedValue
private UUID id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#OneToMany(
mappedBy = "author",
orphanRemoval = true,
fetch = FetchType.EAGER
)
private List<BookEntity> books; // Getters and Setters
}
Here's Book:
#Entity
#Table(name = "books")
public class BookEntity {
#Id
#Column(name = "id")
#GeneratedValue
private UUID id;
#Column(name = "title")
private String title;
#ManyToOne(optional = false)
#JoinColumn(
name = "author_id",
referencedColumnName = "id"
)
private AuthorEntity author;
// Getters and Setters
}
I saved an author and a book through their respective repositories and I checked everything is fine, and here's my query to fetch the author :
SELECT a FROM AuthorEntity a JOIN a.books WHERE a.id = :authorId
Now when I try to access author.getBooks() it says it is null, why doesn't it fetch ? Why do I always have to fetch the books separately ? What's the right query ?

JPA Repository.findByKeyEquals() returns not present value, but the value is exist on db

I'm developing an application that queries a database.
There are a few issues right now.
history.isPresent() == false when calling Optional<History> findByKeyEquals() intermittently. but value is exist on database
This is the information I got while tracking the issue.
All child entities are non-null.
In most cases, if the same function is re-executed, it is searched.
But sometimes it doesn't happen intermittently.
i think that i use incorrectly table relationship annotation (#OneToMany,#ManyToOne options..)
I want to solve this issue.
this is my code
History (Parent)
#Table(
indexes = {
#Index(columnList = "key", unique = true),
})
#Entity
#Getter
#ToString
#Audited
public class History implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(updatable = false, nullable = false, columnDefinition = "BIGINT UNSIGNED")
private Long id;
#Setter
#Column(nullable = false, columnDefinition = "CHAR(36)")
private String key = UUID.randomUUID().toString();
#Setter
#Temporal(TemporalType.TIMESTAMP)
#NotAudited
private Date started = new Date();
#Setter
#Temporal(TemporalType.TIMESTAMP)
#NotAudited
private Date finished;
#Setter
#OneToMany(
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
mappedBy = "history",
orphanRemoval = true)
#NotAudited
private List<Content> contents = new ArrayList<>();
...
}
Content (Child)
#Table
#Entity
#Getter
#Audited
public class Content implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(updatable = false, nullable = false, columnDefinition = "BIGINT UNSIGNED")
private Long id;
#Setter
#Column(columnDefinition = "LONGTEXT")
#NotAudited
private String content;
#Setter
#ManyToOne(targetEntity = History.class, fetch = FetchType.Lazy, optional = false)
#Audited
private History history;
...
}
Repository
public interface HistoryRepository
extends JpaRepository<History, Long>, RevisionRepository<History, Long, Integer> {
Optional<History> findByKeyEquals(final String key);
}

Jackson #JsonIgnoreProperties seems not to work all the time

I mapped two entities to those following classes :
#Getter
#Entity
#Table(name = "users")
#JsonIdentityInfo(generator = PropertyGenerator.class,
property = "id")
#SequenceGenerator(name = "id-generator", sequenceName = "seq_users")
#EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
#NoArgsConstructor(access = PROTECTED)
#RequiredArgsConstructor
public class User extends IdentifiedById {
#Include
#NonNull
#Column(name = "email_address", unique = true)
private String emailAddress;
#Setter
#JsonIgnore
private String hash;
#Setter
private boolean admin;
#OneToMany(
mappedBy = "user",
orphanRemoval = true,
cascade = ALL
)
#JsonIgnoreProperties("user")
private Set<Cart> carts;
{
carts = new HashSet<>(0);
}
}
#Getter
#Entity
#Table(
name = "carts",
uniqueConstraints = #UniqueConstraint(
columnNames = {
"creation_time",
"user_id"
}
)
)
#JsonIdentityInfo(generator = PropertyGenerator.class,
property = "id")
#SequenceGenerator(
name = "id-generator",
sequenceName = "seq_carts"
)
#EqualsAndHashCode(
callSuper = false
)
#RequiredArgsConstructor
#NoArgsConstructor(access = PROTECTED)
public class Cart extends IdentifiedById {
#NonNull
#Column(name = "creation_time")
private LocalDateTime creationTime;
#NonNull
#ManyToOne(cascade = ALL)
#JoinColumn(
name = "user_id",
referencedColumnName = "id"
)
#JsonManagedReference
private User user;
#Exclude
#JsonProperty("productStoreQuantities")
#JsonSerialize(converter = AdditionConverter.class)
#OneToMany(mappedBy = "cart", orphanRemoval = true, cascade = ALL)
private Set<Addition> additions;
{
additions = new HashSet<>(0);
}
}
If I retrieve a user, its carts do not contain its reference, it is fine by me.
Now from a rest endpoint perspective I would like not to serialize users along with their carts if one requests multiple users like so :
**/api/users -> {"id":1, "emailAddress":"test#test.test", "admin": false}**
**/api/users/1 -> {"id":1, "emailAddress":"test#test.test", "admin": false, "carts": [...]}**
Thus, I created a wrapper class named Users containing a list of users annotated with #JsonValue and #JsonIgnoreProperties("carts") :
#RequiredArgsConstructor
public class Users implements Serializable, List<User> {
#Delegate
#JsonValue
#JsonIgnoreProperties("carts")
private final List<User> values;
}
I don't know why but carts keep being serialized, I heard that #JsonIgnoreProperties does not work on collections and arrays but it does in my first case.
You should use JsonIgnoreProperties in a class level.
This is well explained in this post
https://www.baeldung.com/jackson-ignore-properties-on-serialization

Spring Data JPA OneToOne Mapping returning Null

I have two Entity classes, each for my Table. They both are OneToOne-Mapped. When I read the Data, am always getting the other table's value as null.
These are my SQLs
CREATE TABLE driver_master (
unique_driver_id VARCHAR(60) PRIMARY KEY,
driver_name TEXT,
mobile_number VARCHAR (20),
vehicle_number TEXT,
vehicle_make TEXT,
seating_capacity INTEGER (10),
creation_time DATETIME
)
CREATE TABLE user_master (
user_id MEDIUMINT AUTO_INCREMENT PRIMARY KEY,
user_name TEXT,
password VARCHAR (20),
unique_driver_id VARCHAR(60),
FOREIGN KEY (unique_driver_id) REFERENCES driver_master(unique_driver_id)
)
These are my Entity classes
DriverMaster.java
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "driver_master")
public class DriverMaster {
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
#Column(name = "unique_driver_id")
UUID id;
#Column(name = "driver_name")
String driverName;
#Column(name = "mobile_number")
String mobileNumber;
#Column(name = "vehicle_number")
String vehicleNumber;
#Column(name = "vehicle_make")
String vehicleMake;
#Column(name = "seating_capacity")
Integer seatingCapacity;
#Column(name = "creation_time")
OffsetDateTime creationTime;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "driverMaster")
UserMaster userMaster;
}
UserMaster.java
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "user_master")
public class UserMaster {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
Long id;
#Column(name = "user_name")
String userName;
#Column(name = "password")
String password;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "unique_driver_id", nullable = false)
DriverMaster driverMaster;
}
This is my DriverMasterRepository
public interface DriverMasterRepository extends CrudRepository<DriverMaster, Long> {
DriverMaster findById(UUID id);
}
This is my UserMasterRepository
public interface UserMasterRepository extends CrudRepository<UserMaster, Long> {
UserMaster findById(Long id);
}
I am creating DriverMaster and UserMaster at the same time. Code Snippet below
public DriverMaster create() {
UserMaster userMaster = UserMaster.builder()
.userName("xxxxx")
.password("xxxx").build();
DriverMaster driverMaster = DriverMaster.builder().driverName("TestDriver")
.creationTime(ZonedDateTime.now().toOffsetDateTime())
.seatingCapacity(8)
.mobileNumber("xxxxxxx")
.vehicleNumber("xxxx")
.vehicleMake("xxxx")
.userMaster(userMaster)
.build();
return driverUserService.create(driverMaster);
}
When i access each repository and get the data, the data for that particular table is getting populated while the referenced Object is always coming as Null.
After creation of DriverMaster, I couldn't get UserMaster within DriverMaster, it is always coming as null .
The REST Response below shows that UserMaster within DriverMaster is coming as Null
{
"id": "0d97073b-6ae2-47a9-b751-0313fd9e8ba2",
"driverName": "TestDriver",
"mobileNumber": "11111",
"vehicleNumber": "111",
"vehicleMake": "figo",
"seatingCapacity": 8,
"creationTime": "2018-02-16T15:56:50.331Z",
"userMaster": null
}
it's not a 100% problem's reason, but I believe you have to add an implementation of Serializableinterface into your entity classes.

Resources