Want to get collection of an object Spring boot - java

public class Item { #ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) #JoinColumn(name = "headingName", nullable = true) private Heading heading; ... }
public class Heading { #OneToMany(mappedBy = "heading", cascade = CascadeType.ALL) #OrderBy("description ASC") private List<Item> items; ...}
#Repository
public interface HeadingRepository extends JpaRepository<Heading, String> {
List<Heading> findByItemsDescriptionContainsIgnoreCase(String description);
}
#PostMapping("/search")
public String search(#RequestParam("text") String search, Model model) {
List<Heading> headings = headingService.findByItems_Description(search);
return "Index";
}
I got a h2 database connected to the website and I am trying to get a list of heading which includes a list of items but I am getting a list of all items on that heading including the item I search but I need multiple headings and multiple items on that item list. I need only the item or characters that I searched. Please help me.

Related

More than one row with the given identifier was found when calling findAll(), but works if I iterate trough all entries with findById();

Well... I have an auto-generated database by hibernate and when I try to call findAll() in controller I receive that
More than one row with the given identifier was found: 1, for class: com.example.rentacar.domain.Masina
Anyway, I checked database I don t have duplicates keys. This is the controller:
#Controller
public class MasinaController {
MasinaService masinaService;
#Autowired
public MasinaController (MasinaService masinaService){
this.masinaService = masinaService;
}
#RequestMapping("/masini")
public String getMasini(Model model){
var masini = masinaService.findMasini();
model.addAttribute("masini", masini);
return "masini";
}
}
service:
#Autowired
public MasinaServiceImpl(MasinaRepo masinaRepo) {
this.masinaRepo = masinaRepo;
}
public List<Masina> findMasini(){
var masini = masinaRepo.findAll();
return masini;
}
this is the domain:
#Entity
#Data
public class Masina {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String model;
private Integer capacitateCilindrica;
private Integer putere;
private Integer anProductie;
private String culoare;
private String numarInmatriculare;
private Float pret;
private Boolean esteInchiriata;
#OneToOne(mappedBy = "masina")
private ChirieActiva ChirieActiva;
#OneToMany(mappedBy = "masina")
private List<ChirieFinalizata> ChiriiFinalizate;
#OneToOne
private Firma Firma;
#ManyToMany(mappedBy = "Masini",
cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Categorie> CategoriiMasina;
}
The rest of object that are linked are empty(no-entries).
I tried to see what identifier is corrupted so I iterate through all entries to see what id will return me an error. After full iteration none of the entries returned error..
The funniest part is that if I add this code in controller (iterate through all entries from db using findById before calling findAll) it WORKS !!!!
So.. my controller looks like this...
#RequestMapping("/masini")
public String getMasini(Model model){
for(int i=1; i<9;i++){
var masina = masinaService.findById(i);
}
var masini = masinaService.findMasini();
model.addAttribute("masini", masini);
return "masini";
}
Did anyone know why that happens? Thanks a lot!
I solved the problem by adding (fetch = FetchType.LAZY) to #OneToOne relationships.

Parent-Child categories duplicate problem

I have the following problem. I searched everywhere and i couldn't find a similar post. I have an enum(enumerate) file which holds product categories and it's main purpose is when I start the application to fill the database with the categories. The categories are parent-children type. The problem is when I add a category, which has a parent it adds the parent again(it duplicates).
Example:
I have the following categories:
category1
category2 (subcategory of category1)
category3 (subcategory of category1)
In the database it will add cat1, cat2, cat3, cat1, cat1, it will duplicate the parent as many times as a new subcategory is added.
Type.class
#Getter
#Setter
#NoArgsConstructor
#Entity
#Table(name = "types")
public class Type extends BaseEntity {
#Column(name = "name", nullable = false)
private String name;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "parent_id", referencedColumnName = "id")
private Type parent;
#OneToMany(mappedBy = "parent")
private List<Type> children;
}
TypeData.java (enum)
Here I create the categories. If category should have a parent I add it, if not I leave it null.
#Getter
public enum TypeData {
CATEGORY_1("Category 1", null),
CATEGORY_2("Category 2", CATEGORY_1),
CATEGORY_3("Category 3", CATEGORY_1);
private final String name;
private final TypeData parent;
TypeData(String name, TypeData parent) {
this.name = name;
this.parent = parent;
}
}
TypeInitialData.java
When I start the application, this file loads categories to the database.
#Component
public class TypeInitialData {
private final TypeService typeService;
private final ModelMapper modelMapper;
#Autowired
public TypeInitialData(TypeService typeService, ModelMapper modelMapper) {
this.typeService = typeService;
this.modelMapper = modelMapper;
}
#PostConstruct
public void init() {
Arrays.stream(TypeData.values())
.forEach(x -> this.typeService.addType(this.modelMapper.map(x, Type.class)));
}
}
Have you tried setting the getter when it colides with the parent. Also the child must be one of two many, the other must be many to many. delete the second parent and add it in the database.

How to sort related entity in #ManyToMany relationship

There are two entities POST and TAG they are connected by a many-to-many relationship.
Post
#ManyToMany
#JoinTable(name = "posts_tags",
joinColumns = #JoinColumn(name = "post_id"),
inverseJoinColumns = #JoinColumn(name = "tag_id"))
private List<Tags> tags = new ArrayList<>();
Tag
#ManyToMany(mappedBy = "tags")
#JsonIgnore
private List<Posts> posts = new ArrayList<>();
Depending on which Tag I chose, should show me all posts dependent on him.
All posts should be displayed using pagination and sorting which user selects.
The problem is that sorting and pagination are ignored.
My first try
public Page<Posts> getPostsByTag(String tag, Integer page, Integer size, String sort, String dir){
Tags tags = tagsRepository.findByTagName(tag);
Pageable pageable = PageRequest.of(page,size, dir.equals("asc") ? Sort.Direction.ASC : Sort.Direction.DESC,sort);
return new PageImpl<>(tags.getPosts(),pageable,tags.getPosts().size());
}
My second try
public Page<Posts> getPostsByTag(String tag, Integer page, Integer size, String sort, String dir){
Tags tags = tagsRepository.findByTagName(tag);
PagedListHolder pagedListHolder = new PagedListHolder(tags.getPosts());
pagedListHolder.setPage(page);
pagedListHolder.setPageSize(size);
pagedListHolder.setSort(new MutableSortDefinition(sort, true ,dir.equals("asc")));
return new PageImpl<>(pagedListHolder.getPageList());
}
On the second try, pagination works, but sorting doesn't.
How to get tags.getPosts() list sorted?
Try with OrderBy anotation
#ManyToMany(mappedBy = "tags")
#JsonIgnore
#OrderBy("direction")
private List<Posts> posts = new ArrayList<>();
Your first try seems to correct but you have two missing points as I guess.
The first one is, you should definitely make your query for getting posts from the post repository by providing the paging details.
The second one is in order to do that you should define Pageable in your repository as a parameter.
#Repository
public interface PostDao extends JpaRepository<Posts, UUID> {
public Page<Posts> findByTagsName(String name, Pageable pageable);
}
After that you can use your repository in your service like below:
#Override
public Page<Posts> getPostsByTag(String tag, Integer page, Integer size, String sort, String dir) {
PageRequest request = PageRequest.of(page, size, Direction.fromString(dir), sort);
return postDao.findByTagsName(tag, request);
}
This will provide you the expected behavior with the abilities of both paging and sorting dynamically. Hope this helps. Cheers!

Spring Data JPA entity created twice

I have written a service method importCategories() which retrieves a list of categories from database and recursively fills in properties and parent categories. The problem I'm experiencing is that new categories are created twice, except when I annotate complete() with #Transactional. Can anyone explain to me why that is? I save the child before adding it to the parent, and afterwards save the parent which has CascadeType.ALL on the child collection.
Model:
#Entity
public class Category implements Identifiable<Integer> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer key;
private String name;
#ManyToOne
private Category parent;
#OneToMany(mappedBy="parent", cascade = {CascadeType.ALL})
private List<Category> children = new ArrayList<Category>();
public void add(Category category) {
category.setParent(this);
children.add(category);
}
}
Service:
#Transactional
private void complete(Category category) {
// ... (getting category info such as "name" and "parent key" from web service)
category.setName(name);
category = categoryRepository.saveAndFlush(category);
if (category.getParent() == null) {
Category parentCategory = new Category();
parentCategory.setKey(parentKey);
List<Category> categories = categoryRepository.findByKey(parentKey);
if (categories.size() > 0) {
parentCategory = categories.get(0);
}
parentCategory.add(category);
parentCategory = categoryRepository.saveAndFlush(parentCategory);
if (parentCategory.getParent() == null) {
complete(parentCategory);
}
}
}
public void importCategories() {
List<Category> list = categoryRepository.findAll();
for (Category category : list) {
complete(category);
}
}
If you have a cascade ALL type then you dont need to save your child entity first, just the parent.
category.getchildren().add(children)
save(category)
On that moment category will save/update the entity and will do the same for children.
look another examples to understand how works the hibernate cascade: http://www.mkyong.com/hibernate/hibernate-cascade-example-save-update-delete-and-delete-orphan/

Play Framework 2.1 ebean construction

I just started using Play Framework 2.1.1 as a Java developer.
Got some eBeans from an existing database and I'm building a RESTful architecture to serve and save those beans from a RESTful client web application.
I have the following beans definitions. Feed is the core object of the application. For simplicity I have not included getters and setters and many other beans, I'm focusing on the ones that give me troubles:
#Entity
public class Feed extends Model implements Serializable
{
#Id
Long feedId;
...
...
...
#JsonManagedReference("feed-item")
#OneToMany(fetch = FetchType.LAZY, mappedBy = "feed")
List<Item> items;
#JsonManagedReference("feed-userFeed")
#OneToMany(fetch = FetchType.LAZY, mappedBy = "feed")
List<UserFeed> userFeeds;
}
#Entity
public class Item extends Model implements Serializable
{
#Id
Long itemId;
...
...
...
Long urlId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "url_id")
Url url;
#Formats.DateTime(pattern = "yyyy-MM-ddThh:mm:ss")
Timestamp itemPublishedAt;
#Formats.DateTime(pattern = "yyyy-MM-ddThh:mm:ss")
Timestamp itemUpdatedAt;
#Formats.DateTime(pattern = "yyyy-MM-ddThh:mm:ss")
Timestamp createdAt;
#Version
Timestamp updatedAt;
Long feedId;
#ManyToOne(fetch = FetchType.LAZY)
#JsonBackReference("item-feed")
#JoinColumn(name = "feed_id")
Feed feed;
Long urlId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "url_id")
Url url;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "item")
#JsonManagedReference("item-unseen")
List<Unseen> unseen;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "item")
#JsonManagedReference("item-score")
List<Score> scores;
}
#Entity
public class User extends Model implements Serializable
{
#Id
Long userId;
...
...
...
#OneToMany
#JsonManagedReference("user-userFeed")
List<UserFeed> userFeeds;
#OneToMany
#JsonManagedReference("user-userTag")
List<UserTag> userTags;
#OneToMany
#JsonManagedReference("user-unseen")
List<Unseen> unseen;
#OneToMany
#JsonManagedReference("user-score")
List<Score> scores;
}
#Entity
public class Score extends Model implements Serializable
{
#Id
Long scoreId;
...
...
...
Long itemId;
#ManyToOne(fetch=FetchType.LAZY)
#JsonBackReference("score-item")
#JoinColumn(name = "item_id")
Item item;
Long userId;
#ManyToOne(fetch=FetchType.LAZY)
#JsonBackReference("score-user")
#JoinColumn(name = "user_id")
User user;
}
Here's my feed controller:
import me.zenfeed.model.Feed;
import org.codehaus.jackson.JsonNode;
import play.db.ebean.Model;
import play.libs.Json;
import play.mvc.BodyParser;
import play.mvc.Controller;
import play.mvc.Result;
public class FeedController extends Controller
{
public static Result delete(Long id)
{
new Model.Finder<>(Long.class, Feed.class).byId(id).delete();
return ok();
}
/* return a JSON with all of the objects found*/
public static Result get()
{
return ok(Json.toJson(new Model.Finder<>(Long.class, Feed.class).fetch("userFeeds", new FetchConfig().query()).where().eq("userFeeds.userId", Long.parseLong(session("connectedUserId"))).findList()));
}
/* accept a JSON with the object to save and return a JSON with the new object*/
#BodyParser.Of(BodyParser.Json.class)
public static Result post()
{
JsonNode json = request().body().asJson();
Feed f = Json.fromJson(json, Feed.class);
f.save();
return ok(Json.toJson(f));
}
/* accept a JSON with the object to save and return a JSON with the new object*/
#BodyParser.Of(BodyParser.Json.class)
public static Result put(Long id)
{
JsonNode json = request().body().asJson();
Feed f = Json.fromJson(json, Feed.class);
f.update(id);
return ok(Json.toJson(f));
}
}
Here's a custom function I use to make a query on the DB with some parameters:
List<Item> l = new Model.Finder<>(Long.class, Item.class)
.select("itemId, feedId, urlId, title, description, content, author, categories, itemPublishedAt, itemUpdatedAt, wordCount, fresh, vector, createdAt, updatedAt")
.fetch("unseen", "itemId", new FetchConfig().query())
.fetch("scores", "score", new FetchConfig().query())
.fetch("feed.userFeeds", "userId", new FetchConfig().query())
.where()
.eq("feed.userFeeds.userId", Long.parseLong(session("connectedUserId")))
.eq("feed.feedId", feedId)
.orderBy("scores.score")
.findList();
I have several problems I would like help with:
- When I try a POST request that calls the method post() of this controller I get the following exception:
[RuntimeException: org.codehaus.jackson.map.JsonMappingException: Can not handle managed/back reference 'user-score': no back reference property found from type [collection type; class java.util.List, contains [simple type, class me.zenfeed.model.Score]]]
I think I put the back reference in the Score model correctly, but I don't understand... Are my ebeans correct?
Is there something wrong in my controller? Can something be made better?
I now understand I saw a wrong tutorial. The argument for #JsonManagedReference and #JsonBackReference must be the same. So for feed-item relationship the correct annotations are #JsonManagedReference("feed-item") and #JsonBackReference("feed-item").
As you can see I tried to format the Timestamp objects with an HTML5 like format, but with no luck. I always get the Long number. Should I make a conversion to a Date object? If yes where?
- When I run the query with my custom function I get the URL object populated, even though I clearly excluded it from my select statement (I only would like the URL_ID, not the entire object).
I went manual way with the generation of an HashMap for the properties I care of and gave that to the Json.toJson() method.
Thank you for your help.

Categories