W ramach nauki Springa piszę sobie prostą aplikacyjkę restową. Umożliwia ona dodawanie postów, komentarzy, upvotów. Używam do tego Spring Data JPA, do prostych operacji CRUD spisuje się to naprawdę dobrze.
Teraz moim zadaniem jest pobranie wszystkich postów posortowanych po ilości upvotów i komentarzy. JSON powinien zawierać takie pola jak: postid, userid, description, adddate, upvote count, comment count.
Pierwsza myśl to utworzenie widoku w bazie danych, oparcie encji na nim i voila. Zrobiłem, działa. Tylko znowu myślę sqlowo, bazo-centrycznie. No i nie jest persist.
Próbowałem przenieść to na obiekty, ale mi nie idzie. Zostałem z JPQL i trochę śmieciowym kodem (encję Users i Comments pomijam, są proste):
@Entity
public class Upvote {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long upvoteId;
@JsonIgnore
@ManyToOne
private Users user;
private UpvoteType type;
private Long toId;
private Date addDate = new Date();
public Upvote() {
}
public Upvote(Users user, UpvoteType type, Long toId) {
this.user = user;
this.type = type;
this.toId = toId;
}
//getters
}
public enum UpvoteType {
POST, COMMENT;
}
Upvote można dać do postu i komentarza. Nie ma klucza obcego, tylko pole toId. W ten sposób chcę łatwo w przyszłości dodać upvote do filmów, zdjęć itp.
Nieszczęsny POST
@Entity
public class Post implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long postId;
@ManyToOne
private Users user;
private UpvoteType upvoteType = UpvoteType.POST;
@JsonIgnore
@OneToMany
@JoinColumns({
@JoinColumn(updatable = false, insertable = false, name = "toId", referencedColumnName = "postId"),
@JoinColumn(updatable = false, insertable = false, name = "type", referencedColumnName = "upvoteType")
})
private Set<Upvote> upvote;
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Comments> comment = new ArrayList<>();
private String description;
private Date addDate = new Date();
//constructors/getters
}
Chcę tylko wybrane pola, więc DTO:
public class GreatestPostsDto {
private Long postId, userId;
private String description;
private Date addDate;
private Long upvoteCount;
private Long commentCount;
public GreatestPostsDto(Long postId, Long userId, String description, Date addDate, Long upvoteCount, Long commentCount) {
this.postId = postId;
this.userId = userId;
this.description = description;
this.addDate = addDate;
this.upvoteCount = upvoteCount;
this.commentCount = commentCount;
}
//getters
Repozytorium:
@Repository
public interface GreatestPostsRepository2 extends JpaRepository<Post, Long> {
@Query(value = "select new pl.herasoft.test.springappka1.dto.GreatestPostsDto(p.postId, p.user.userId, p.description, p.addDate, count(upv.upvoteId) as upvoteCount, count(c.commentId) as commentCount) "
+ "from Post p "
+ "left join p.comment c "
+ "left join p.upvote upv "
+ "group by p.postId, p.user.userId, p.description, p.addDate "
+ "order by upvoteCount desc, commentCount desc")
List<GreatestPostsDto> findGreatestPosts();
}
I wreszcie pytanie, czy da się to zrobić bez JPQL tylko na obiektach, tak żeby przy każdym requescie nie jechało po bazie?