I was trying to use #Formula in one of my entity classes.
What I need to do is select a boolean from another entity.
I tried to put the property definition but it keeps throwing a NullPointerException when publishing, I did it as follows
#JoinColumn(name = "SOIR08_FECHA_CARGA", referencedColumnName = "SOIR15_CODI_FECHA", nullable = true)
#ManyToOne(fetch = FetchType.EAGER)
private FechaCarga loadDate;
#JoinColumn(name = "SOIR08_RECEPTOR", referencedColumnName = "SOIR05_CON_DISTRITO_TELEFONICO", nullable = true)
#ManyToOne(optional = true, fetch = FetchType.EAGER)
private DistrictPhone receiver;
#Formula("(select io.done from Table io where io.district = receiver and io.loadDate = loadDate)")
private Boolean isDone;
Then I tried putting the #Formula annotation in the getter
#Formula("(select io.done from Table io where io.district = receiver and io.loadDate = loadDate))")
public Boolean getIsDone() {
return isDone;
}
but when I access the page where the property must be shown I get ORA-00904: "APROB0_"."ISDONE": invalid identifier
Any idea,suggestion or workaround will be highly appreciated.
You have to write pure SQL in the #Formula (but not HQL).
I couldn't find a way to use this annotation without getting errors.
What I decided to do was to add a column in the table, and fill it when a insert was made, not the best way but I needed to do it fast and there was nothing on forums that worked for me.
Thanks.
Related
I have problem with unidirectional mapping and need help.
I have 2 Entities with the same unidirectional mapping.
The first one:
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "massnahme_id", nullable = false)
private Set<VerortungDAO> verortungen = new LinkedHashSet<>();
The second one:
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "massnahmen_verbund_id", nullable = false)
private Set<VerortungDAO> verortungen = new LinkedHashSet<>();
If I try to save one Entity, hibernate throws an Exception because of the second Entity definition (not null).
org.hibernate.PropertyValueException: not-null property references a
null or transient value
If I change the JoinColumn to nullable = true, then the unidirectional mapping not working and the list is not saved in DB.
What can I do to make it work?
Make the associations bidirectional and map the to-one association in VerortungDAO, or if you don't want that, at least map the FK-columns. If you map it bidirectional, use #OneToMany(mappedBy = "..."). Either way, you will have to initialize the two to-one associations or FK-columns on the VerortungDAO objects.
PS: An entity isn't a DAO (data access object), so the naming xxDAO is quite confusing for an entity.
I have following classes and on annotating #BatchSize annotation it is not working and I am getting n+1 select query.
Class Shipment{
#OneToMany(fetch = FetchType.LAZY, mappedBy = order.shipment, cascade = CascadeType.ALL,
orphanRemoval = true)
#BatchSize(size=20)
Set<Orders> orders = new Hashset(); <---- Batch size annotation not working
}
Order.class
class Order{
#ToString.Exclude
#ManyToOne
#JoinColumn(name = "item_fk")
Item item;
#ToString.Exclude
#ManyToOne
#JoinColumn(name = "shipment_fk")
Shipment shipment; }
Item.class
class Item{
String id;
String name;
}
What is mistake in implementation that i am getting n+1 queries?
Try to use List<Orders> instead of Set<Orders>.
Please note as it's mentioned in the documentation:
However, although #BatchSize is better than running into an N+1 query issue, most of the time, a DTO projection or a JOIN FETCH is a much better alternative since it allows you to fetch all the required data with a single query.
Your N + 1 query issue is due to the fact that you do eager fetching of Item in Order. Change to LAZY there and you should be good to go.
I need for a project to join 2 SQL tables implemented like this :
I know that I'm not supposed to implement the table IngredientList as an object cause it's only here for SQL structure.
My code goes like this :
#Entity
#Table(name="recipe")
public class Recipe {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_recipe")
private Long id;
#OneToMany
#JoinTable(name="liste_ingredients", joinColumns = #JoinColumn(name = "id_recette",
referencedColumnName = "id_recette"),
inverseJoinColumns = #JoinColumn(name = "id_ingredient",
referencedColumnName = "id_ingredient"))
List<Ingredient> ingredients;
/* Getter/Setter/Constructor */
}
Which is the classic way but with that I lose the Quantity attribute that I want to associate with ingredient. And I don't get how I can work around this without creating an object IngredientList.
Thanks in advance.
Nevermind that I got my answer gonna edit it soon with code, for anyone with the same question.
I am having these Entities: DocumentType, UserGroup, User
DocumentType.java has #ManyToMany Set of UserGroup:
#ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinTable(name = "review_type", joinColumns = #JoinColumn(name="doc_type"),
inverseJoinColumns = #JoinColumn(name="user_group_id") )
private Set<UserGroup> reviewUserGroups;
UserGroup.java has #ManyToMany Set of User:
#ManyToMany
#JoinTable(name = "group_users", joinColumns = #JoinColumn(name = "group_id"),
inverseJoinColumns = #JoinColumn(name = "user_id"))
private Set<User> users;
What I want to do implement this code:
#Transactional
private void createDocuments(int avgDocsPerUser) {
List<DocumentType> documentTypes = documentTypeRepository.findAll();
int documentTypesCount = documentTypes.size();
List<User> users = userRepository.findAll().stream().filter(user -> !user.isAdmin()).collect(Collectors.toList());
int usersCount = users.size();
int documentsToCreate = (int) Math.floor(Math.random() * (usersCount * avgDocsPerUser)) + 1;
List<Document> documentList = new ArrayList<>();
while (documentList.size() < documentsToCreate) {
DocumentType documentType = documentTypes.get((int) Math.floor(Math.random() * documentTypesCount));
User user = documentType
.getSubmissionUserGroups()
.stream().findAny()
.get().getUsers()
.stream().findAny().get();
// create new document here and add User info to it
}
documentRepository.saveAll(documentList);
}
The problem that I keep getting error:
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: it.akademija.wizards.entities.DocumentType.submissionUserGroups, could not initialize proxy - no Session
I want to avoid EAGER fetching. How to implement this code so I can randomly get User that is a part of UserGroup which is a part of SubmissionUserGroups in DocumentType object.
Part of your problem is likely that you've used the #Transactional annotation on a private method. According to the docs, this doesn't work:
When using proxies, you should apply the #Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the #Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.
In addition, I find the way you get a User from the document type a bit hard to understand. Part of the issue there is the number of time you stream through collections, find something, and then stream through another collection.
It might be easier (and more in line with Spring idioms) to inject the UserRepository into this class and do a separate query here. If this method is also public, I believe it would be included in the same transaction so you wouldn't suffer the performance overhead of having to open another session.
However, you should do some more research on this. You might find this other post helpful: How to load lazy fetched items from Hibernate/JPA in my controller.
I'm new in Spring, Hibernate, JPA and it's API. I've created a #RestController and the related method is like,
#GetMapping("/user")
public ResponseEntity getListItemById(){
UserTypeEntity entity = userTypeRepository.findFirstByUserTypeId(1);
return ResponseEntity.ok().body(entity);
}
UserTypeEntity has 2 lazy getters,
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "user_id", referencedColumnName = "user_id", nullable = false)
public UserEntity getUserByUserId() {
return userByUserId;
}
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "user_type_list_item_id", referencedColumnName = "list_item_id", nullable = false)
public ListItemEntity getListItemByUserTypeListItemId() {
return listItemByUserTypeListItemId;
}
All the properties of ListItemEntity and UserEntity are null until and unless I use JOIN FETCH query. I've checked and verified that one.
(It might be familiar to any experienced)
Looks like following.
Here is the sample response I use to get,
(Sorry it couldn't even be formatted because of large data response, though I have single row in each table. It's Infinite recursion (StackOverflowError))
Everything is loaded eventually. I couldn't identify what the heck going wrong here. Why these lazy null properties are loaded and I got this weird and vague response? I've wasted whole day on this, plz help to get out of this.
Move your annotations from getter to field declaration and you will see consistent results.
After your edit:
#ShreeKrishna that was my point. Now I can provide clear explanation that this is expected behavior. Debugger shows you what fields are actually are and those are and WILL BE null as your lazy intitialization trigger is on GETTER method, not on field. So, don't pay attention to what debugger is showing you as long as you will access your properties via getters instead of direct access - you will be fine.