LazyInitializationException could not initialize proxy - no Session - jpa

My problem is that I'm getting LazyInitializationException.
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:148) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:266) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:73) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at sk.kristian.dienes.eshop.entity.SubCategory_$$_jvsta89_5.hashCode(SubCategory_$$_jvsta89_5.java) ~[main/:na]
at sk.kristian.dienes.eshop.entity.Product.hashCode(Product.java:18) ~[main/:na]
I have two #ManyToOne relationships in one class
public class Product implements Serializable{
#Id
#Column(name = "id")
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_category")
private Category category;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_sub_category")
private SubCategory subCategory;
}
#Entity
#Data
public class SubCategory implements Serializable {
#OneToMany(mappedBy = "subCategory", cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private List<Product> products;
}
#Entity
#Data
public class Category implements Serializable {
#OneToMany(mappedBy = "category", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Product> products;}
I'm using HttpSession.
I've also tried to add this property spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true but It did not helped. I would like to know if there is any solution. Also tried to use Transactional anotation in services.

The problem is you try to call object that is detached.
For example)
Product product = em.find(Product.class, id)
// somewhere `em.detach(product)` is called.
product.getCategory(); // It raises Exception
I don't know what you try with those objects. But you should reattach entity to EntityManager like em.merge(detachedObject)
Check state of EntityManager
https://vladmihalcea.com/a-beginners-guide-to-jpahibernate-entity-state-transitions/

Related

duplicate results when sorting by collection property

Repost from here
Given entities and repository:
#Entity
public final class Partner {
#Id
private String id;
#OneToMany(mappedBy = "partner", fetch = FetchType.LAZY)
private List<Merchant> merchants;
...
}
#Entity
public final class Merchant {
#Id
private String id;
#Column
private String name;
#ManyToOne(fetch = FetchType.LAZY)
private Partner partner;
...
}
public interface PartnerRepository
extends JpaRepository<Partner, String>, QueryDslPredicateExecutor<Partner> {
}
If there is only one partner having two merchants in the DB then the following code incorrectly returns list with two instances of the same parnter.
partnerRepository.findAll(new Sort("merchants.name"));
This is caused internally by the DB join. By creating custom implementation that adds the distinct to the selection the result is correctly the single partner.
Wouldn't it be correct to do distinct selection per default?
Try
#OneToMany(mappedBy = "partner", fetch = FetchType.LAZY)
#OrderBy("name")
private List<Merchant> merchants;

JPA #ManyToOne CascadeType.PERSIST

Hallo I have an entity with a #ManyToOne Relations ship
#Entity
public class TerminEntity extends AbstractEntity implements Serializable {
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "PERSON_ID")
private PersonEntity person;
#MappedSuperclass
public abstract class AbstractEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "termineIdGenerator")
#SequenceGenerator(name="termineIdGenerator", sequenceName = "SEQ_TERMINVERWALTUNG")
private Long id;
When I try to persist a TerminEntity with an PersonEntity which is not already present in the database I get
java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: TerminEntity(person=PersonEntity
Why? What is wrong with the #ManyToOne(cascade = CascadeType.PERSIST) annotation?
Running on Oracle Weblogic 12c
I don't know why but after changing the annotation to
#ManyToOne(optional = false, cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH })
#JoinColumn(name = "PERSON_ID", referencedColumnName = "ID", nullable = false)
the persist works.

JPA two Entities one Relationship: How do I obtain a Set of an entity that is linked through a relationship?

I have three tables each mapping to one of these entities. The 'assigned' table acts as the relationship between 'users' and 'roles' with a foreign key to each table. How would I map this on my entities so that I can get a Set of EntityRoles from the UserEntity? I can't quite figure out how to make this work. Is this even possible?
#Entity
#Table(name = "users")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="user_id")
private long id;
#Column(name="user_username")
private String username;
#Column(name="user_password")
private String password;
#Column(name="user_email")
private String email;
//I want to be able to get a set of RoleEntities
#OneToMany(fetch = FetchType.LAZY, mappedBy = "id")
private Set<RoleEntity> roles;
}
#Entity
#Table(name = "assigned")
public class AssignedEntity implements Serializable {
#Id
//#Column(name = "assigned_role")
#ManyToOne(targetEntity = RoleEntity.class, fetch = FetchType.LAZY)
#JoinColumn(name = "fk_role")
private long roleId;
#Id
//#Column(name = "assigned_user")
#ManyToOne(targetEntity = UserEntity.class, fetch = FetchType.LAZY)
#JoinColumn(name = "fk_user")
private long userId;
}
#Entity
#Table(name = "roles")
public class RoleEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="role_id")
#OneToOne(fetch = FetchType.LAZY, mappedBy="roleId")
private long id;
#Column(name="role_name")
private String name;
}
You are using an incorrect/inconvenient mapping. Always keep things as simply as possible.
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue
private Long id;
#ManyToMany(fetch = FetchType.LAZY)
private List<Role> roles;
}
#Entity
#Table(name = "roles")
public class Role {
#Id
private Long id;
#Column
private String name;
}
A persistent provider will create a (valid) join table for you. You can specify the name of the join table using #JoinTable annotation. Also you will need to think about auto generation values of id for the Role entity: the roles table is something like a reference data table. So, probably, you will need to hardcode the id values.
To get user roles (in the persistent context):
user.getRoles()

how to manage jpa bidirectional relation ships correctly?

I am using EJB3.2 and JPA 2.1.
In my application I have these entities (in brief) :
#Entity
public class Festival
{
int Id;
String name;
...
#ManyToOne
#JoinColumn(name = "merchant", referencedColumnName = "Id")
Merchant merchant;
}
#Entity
public class Merchant
{
int Id;
String name;
...
#ManyToOne
#JoinColumn(name = "category", referencedColumnName = "Id")
Category category;
#ManyToOne
#JoinColumn(name = "city", referencedColumnName = "Id")
City city;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "festival")
List<Festival> festivalList;
}
#Entity
public class Category
{
int Id;
String name;
...
#OneToMany(cascade = CascadeType.ALL, mappedBy = "merchant")
List<Merchant> merchantList;
}
#Entity
public class City
{
int Id;
String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "merchant")
List<Merchant> merchantList;
}
thus, (Festival, Merchant) has a bidirectional relationship like (Merchant, Category) and (Merchant, City)
the problem is when i remove or change a merchant, still there is an unchanged copy of it in categories merchantList and cities merchantList ! and so on..
how should I manage these changes?! why JPA doesn't do the changes to other copies it self? doesn't it increase the wrong copies risk?!
JPA treats your entities like regular java objects and does not maintain relationships for you - the application is responsible for ensuring that both sides of a bidirectional relationship are kept in sync when you change one side. So when you dereference a City from a Merchant, you must remove the reference to the Merchant from the City's merchantList and then merge if necessary.
Otherwise your view of the data via the java objects will become out of synch with the database until the objects are refreshed from the database. You can weigh the value and costs of keeping both sides in sync or refreshing when needed or even not mapping the non-owning side and determine what is better for your application on an entity by entity basis.
Make sure to persist(merchant) before calling categories.getMerchantList().
I think this quote from "Java Persistence With Hibernate" (p. 261) by Christian Bauer and Gavin King may be useful for you :
Contrary to EJB 2.0 CMR, Hibernate and JPA associations are all
inherently unidirectional.
So the association from Merchant to Category is different than association from Category to Merchant, and you need to manage them separately.
edit:
I adjusted your initial bean config to look as it should:
(Of course, you will use an appropriate primary key generation strategy.)
#Entity
public class Festival
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
int Id;
String name;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "merchant")
Merchant merchant;
}
#Entity
public class Merchant
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
int Id;
String name;
#ManyToOne
#JoinColumn(name = "category")
Category category;
#ManyToOne
#JoinColumn(name = "city")
City city;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "merchant")
List<Festival> festivalList;
}
#Entity
public class Category
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
int Id;
String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "category")
List<Merchant> merchantList;
}
#Entity
public class City
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
int Id;
String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "city")
List<Merchant> merchantList;
}

one side set in many-to-many relation

I have three database tables: Customer, Product and PurchaseOrder (for mapping). I am using openjpa for peristence in java rest application.
To all of the tables I have corresponding entities:
Customer
#Entity
#Table(name = "customer")
#XmlRootElement
#NamedQueries({...})
public class Customer implements Serializable {
...
#OneToMany(cascade = CascadeType.ALL, mappedBy = "customerId")
private Collection<PurchaseOrder> purchaseOrderCollection;
Product
#Entity
#Table(name = "product")
#XmlRootElement
#NamedQueries({...})
public class Product implements Serializable {
...
#OneToMany(cascade = CascadeType.ALL, mappedBy = "productId")
private Collection<PurchaseOrder> purchaseOrderCollection;
PurchaseOrder
#Entity
#Table(name = "purchase_order")
#XmlRootElement
#NamedQueries({..})
public class PurchaseOrder implements Serializable {
...
#Id
#Basic(optional = false)
#Column(name = "order_num")
private Integer orderNum;
#JoinColumn(name = "customer_id", referencedColumnName = "customer_id")
#ManyToOne(optional = false)
private Customer customer;
#JoinColumn(name = "product_id", referencedColumnName = "product_id")
#ManyToOne(optional = false)
private Product product;
What is the best way to get all the customers who ordered a product with specific id?
I could create namedQuery, I could build criteria with joins etc. But i think there could be a better way how to make use of the mapping entity (what would be point of this entity otherway?). Something like setting the productId to the purchaseOrder entity and then fetch all the customers via purchaseOrderCollection in customer entity? But i cannot figure it out. Is there other way than custom/named query or criteria building?
Thanks.
ok I figured it out, it can be this way
long productId = //get the id
Product product = entityManager.find(Product.class, productId);
Collection<PurchaseOrder> purchaseOrderCollection = product.getPurchaseOrderCollection();
if (purchaseOrderCollection != null) {
List<Integer> customers = new ArrayList<>(product.getPurchaseOrderCollection().size());
for (PurchaseOrder purchaseOrder : product.getPurchaseOrderCollection()) {
customers.add(purchaseOrder.getCustomerId());
}
return customers;
} else {
return Collections.EMPTY_LIST; // or null;
}
feel free to offer better sollution :)