Hibernate problem - “Use of #OneToMany or #ManyToMany targeting an unmapped class” - java

I have 2 entities, LCPUserDetails and LCPUserPrivilege. LCPUserDetails has a List class member, so a One to Many relationship. When I run my unit test I am getting this exception:
#Entity
#Table(name = "LCP_USER_DETAILS")
public class LCPUserDetails {
#OneToMany(orphanRemoval = true, cascade = {CascadeType.ALL},
mappedBy = "userDetails")
private List<LCPUserPrivilege> privileges= new ArrayList<>();
}
#Entity
#Table(name = "LCP_USER_PRIVILEGE")
public class LCPUserPrivilege {
#ManyToOne
#JoinColumn(name = "USER_ID")
private LCPUserDetails userDetails;
}

As Sheik Sena Reddy mentioned, you have to update your list of entities. If you don't use an xml file, you can check where you set your EntityManagerFactory and add a list of package that your EMF will scan to list your entities emf.setPackagesToScan(['my.package.to.scan']);.

Related

how to avoid AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class?

I had an existing class like this - a.b.c.Message.java
#Entity
#Table(name = "Message", indexes = { #Index(name = "messageIdIndex", columnList = "messageId"),
#Index(name = "customerIndex", columnList = "customer")})
public class Message extends BaseEntity {
///other fields and columns...
#JsonIgnore
#OneToMany(mappedBy = "msg",cascade = CascadeType.ALL)
private List<Application1> app1;
/// *newly added
#JsonIgnore
#OneToMany(mappedBy = "msg",cascade = CascadeType.ALL)
private List<Application2> app2;
/// setters and getters and toString() and equals() overridden
and second class: a.b.c.Application1.java
#Entity
#Table(name = "Application1", indexes = { #Index(name = "applicationIdIndex", columnList = "app1Id"),
#Index(name = "customerIndex", columnList = "customer")})
public class Application1 extends BaseEntity {
/// other fields and columns
#ManyToOne(cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH }, optional = true)
private Message msg;
///setter and getters and other methods
}
this works fine, however when I add another class - a.b.c.d.Application2.java:(* and the second field app2 in Message class is added )-
#Entity
#Table(name = "Application2", indexes = { #Index(name = "application2IdIndex", columnList = "app2Id"),
#Index(name = "customerIndex", columnList = "customer")})
public class Application2 extends BaseEntity {
/// other fields and columns
#ManyToOne(cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH }, optional = true)
private Message msg;
///setter and getters and other methods
}
now, when I try to create the EntityManagerFactory I get an exception like this -
Caused by: org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class: a.b.c.Message.app2[a.b.c.d.Application2]
at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1196)
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:799)
at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:724)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:54)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1621)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1589)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:278)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:848)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:876)
at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:58)
... 46 common frames omitted
here's what I tried
read in some answers to a similar issue to check if the Entity annotation is from javax.persistence package instead of the hibernate package
missing Entity annotation - not the case
i have some doubts that this could be beacuse my new class in inside a sub package ,but the exception was there even after moving the class to the base package (a.b.c)
Got the issue, the new class had to be added in the persistence.xml, didn't face this issue as other newly added entity are using spring data jpa, while the older entities are using hibernate (currently transitioning from hibernate to jpa) , however one of the newly added entity was being used in the older classes which relied on the xml for finding entities.

Spring JPA can't persist collection item with related existing entity - detached entity passed to persist

I got an issue when trying to persist an item of a collection and one of its properties is an already persistent entity in a database.
Trying to clarify by this simplified example:
Class A has a List of class B (One to Many, mappedBy, CascadeType.PERSIST, CascadeType.MERGE)
Class B is related back to A (Many to One, JoinColumn)
Class B inherits from BParent (Single Table)
BParent is related to class C (Many to One, CascadeType.MERGE, CascadeType.PERSIST)
When i run ARepository.save(entity) passing a complete object to it (with a List of B including one B entity with a new C associated) it persists all entities normally.
When i run ARepository.save(entity) passing an object related with existing (with List of B including a B entity realted with a EXISTING C associated, i.e. id only) it triggers the dettached entity passed to persist error.
org.hibernate.PersistentObjectException: detached entity passed to persist: C
What im trying to do is to save a new related object (when it has no id) or associate to an existing object (when it has an id).
My respositories are all Spring Data JpaRepository interfaces. My code goes like this (getters and setters ommited):
#Entity
public class A {
#OneToMany(mappedBy = "bEntity", cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
private List<B> bList = new ArrayList<>();
}
#Entity
#DiscriminatorValue("B")
public class B extends BParent {
#ManyToOne
#JoinColumn(name = "CVLE_CVL_UUID")
private A bEntity;
}
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "CVLE_TIPO")
#Table( name = "TAB_CONTA_VINCULADA_LANC_EMPREGADO")
public abstract class BParent {
#Id
private UUID id;
#ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST})
#JoinColumn(name = "CVLE_EMP_UUID")
private C cEntity;
}
#Entity
#Table( name = "TAB_EMPREGADO")
public class C {
#Id
#Column(name = "EMP_UUID")
private UUID id;
}
I hope i could explain it right (english is not my first language). I would appreciate if someone could give me a hand on this, thank you.

Spring Data JPA persisting one to many referenced entity

I am using Spring Data JPA (1.4.0, spring boot) and have following code
ExternalOrder entity:
#Entity
#Table(name = "External_Orders")
public class ExternalOrder {
...
#OneToMany(fetch = FetchType.LAZY, mappedBy = "externalOrder", orphanRemoval = true, cascade = CascadeType.ALL)
private List<ExternalOrderElement> elements;
...
}
ExternalOrderElement entity:
#Entity
#Table(name = "External_Order_Elements")
public class ExternalOrderElement implements Serializable {
#Id
#ManyToOne(optional = false)
#JoinColumn(name = "ExternalOrderID")
private ExternalOrder externalOrder;
#Id
#OneToOne(optional = false)
#JoinColumn(name = "BoardGameID")
private BoardGame boardGame;
...
}
I also have default Crud repository for ExternalOrder
public interface ExternalOrderRepository extends CrudRepository<ExternalOrder, Integer>{
}
And I want to add some element to external order and persist it. I've managed to do this creating my custom repostitory interface and implementing it, but I've now tried to move the logic to the service method like so:
#Override
#Transactional
public void addElementToExternalOrder(int externalOrderId, ExternalOrderElement element) {
ExternalOrder externalOrder = findExternalOrderById(externalOrderId);
element.setExternalOrder(externalOrder);
externalOrder.getElements().add(element);
externalOrderRepository.save(externalOrder);
}
And that results in following Exception upon execution
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'ExternalOrderID' cannot be null
Is there something I am missing about the JPA? It seems like I haven't set the ExternalOrder reference on ExternalOrderElement, but I've done it.
Thank you guys for help in advance.

UnsupportedOperationException when updating cascading children in Spring+JPA

I'm using OneToMany mapping in my SpringBoot project, while I'm having problems when updating the children along with parent update, sample code is like below:
User.java
#Table(name = "user")
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
#OneToMany(mappedBy = "groupUser", cascade = {CascadeType.ALL}, orphanRemoval = true)
private List<UserGroup> userGroups = new ArrayList<>();
}
UserGroup.java
#Table(name = "user_group")
#Entity
public class UserGroup {
#Id
#GeneratedValue
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="user_id")
private User groupUser;
}
SampleUsageCode.java
#Service
public class UserService {
#Autowired
private UserRepository userRepositry;
#Transactaional
public batchUpdateUsers(Collection<User> toBeSavedUsers) {
Map<Integer, User> toBeSavedIdUserMap = toBeSavedUsers.stream()
.collect(groupBy(User::getId(), toList()));
Collection<User> existingUsers = userRepositry.findByIdIn(toBeSavedIdUserMap.entrySet().stream()
.map(Map.Entry::getKey).collect(toList()));
existingUsers.forEach(user -> user.getUserGroups().add(toBeSavedIdUserMap.get(user.getId()).getUserGroups()));
}
}
To simplify the problem, Let's just assume the user groups in to-be-saved users is totally different with the existing ones in the database. The problem is when I try to add new user groups to existing users, it throws java.lang.UnsupportedOperationException. It seems the persistentBag type of userGroups in User is not editable.
I tried with just creating a new collection to store both existing and new user groups, but another error with A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance occurs when I try to save the updated users. How can I achieve this cascading-children merge requirement?
So the problem is caused by that the user groups list I prepared for the test is Unmodifiable

#ManyToMany - data does not persist in Database

Simplifying, in my database I have tables:
Car (pk="id_car")
CarAddon (pk="id_car_fk,id_addon_fk",
`FK_car_addon_addon` FOREIGN KEY (`id_addon_fk`) REFERENCES `addon` (`id_addon`)
`FK_car_addon_car` FOREIGN KEY (`id_car_fk`) REFERENCES `car` (`id_car`)
Addon (pk="id_addon")
Shortly: I have cars, many cars can has many addons (like ABS etc).
There are tables with cars, addons, and one table which is logical connection.
Overall, entities work fine. I have no problems with persist data, when I want persist single object. I don't have problems, when I want FETCH data, ie. Car->getAddon();
But, when I'm going to persisting a collection, nothing happens. No exceptions were thrown, there were no new data in database.
//DBManager is a singleton to create an EntityManager
EntityManager em = DBManager.getManager().createEntityManager();
em.getTransaction().begin();
Addon addon1 = new Addon();
addon1.setName("czesc1");
em.persist(addon1);
Addon addon2 = new Addon();
addon2.setName("czesc2");
em.persist(addon2);
car.setAddonCollection(new ArrayList<Addon>());
car.getAddonCollection().add(addon1);
car.getAddonCollection().add(addon2);
em.persist(car);
em.getTransaction().commit();
In this case, addons were stored in Addon table, car in Car table. There are no new data in CarAddon table though object car has good data (there is addon collection in debbuger).
When I changed em.persist(car) to em.merge(car) I got an exception:
"SEVERE: Persistence error in /admin/AddAuction : java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: model.entity.Car[ idCar=0 ]."
Simple version of my classess:
#Entity
#Table(name = "addon")
#XmlRootElement
#NamedQueries({...})
public class Addon implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#NotNull
#Column(name = "id_addon")
private Integer idAddon;
#Size(max = 100)
#Column(name = "name")
private String name;
#JoinTable(name = "car_addon",
joinColumns = {
#JoinColumn(name = "id_addon_fk", referencedColumnName = "id_addon")},
inverseJoinColumns = {
#JoinColumn(name = "id_car_fk", referencedColumnName = "id_car")})
#ManyToMany
private List<Car> carCollection;
#XmlTransient
public List<Car> getCarCollection() {
return carCollection;
}
public void setCarCollection(List<Car> carCollection) {
this.carCollection = carCollection;
}
}
#Entity
#Table(name = "car")
#XmlRootElement
#NamedQueries({...)
public class Car implements Serializable {
#ManyToMany(mappedBy = "carCollection", fetch= FetchType.EAGER, cascade=CascadeType.ALL)
private List<Addon> addonCollection;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#NotNull
#Column(name = "id_car")
private Integer idCar;
#XmlTransient
public List<Addon> getAddonCollection() {
return addonCollection;
}
public void setAddonCollection(List<Addon> addonCollection) {
this.addonCollection = addonCollection;
}
}
How can I fix it?
ps1. I have:
cascade=CascadeType.ALL przy #ManyToMany private List<Car> carCollection
but this dos not solve my problem.
ps2. I am using Netbeans 7, EclipseLink and MySQL (not Hibernate - I have problem with it)
I have one theory that always seems to trip people up with many-to-many collections. The problem is that in memory, the associations are made in two places. Both in the car's addons list and in the addon's cars list. In the database, there isn't such a duplication.
The way JPA providers get around this is through the mappedBy attribute. Since you have mappedBy on the car's addons list this means that the relationship is actually controlled by the addon's cars list (confusing I know).
Try adding the following:
addon1.setCarCollection(new ArrayList<Car>());
addon1.getCarCollection().add(car);
addon2.setCarCollection(new ArrayList<Car>());
addon2.getCarCollection().add(car);
before you persist the car.
Generally speaking, I would avoid many-to-many associations. What you really have is an intermediate link table, with a one-to-many and a many-to-one. As soon as you add anything of interest to that link table (e.g. datestamp for when the association was made), poof, you are no longer working with a pure many-to-many. Add in the confusion around the "owner" of the association, and you're just making things a lot harder than they should be.
could you try add
#JoinTable(name = "car_addon",
joinColumns = {
#JoinColumn(name = "id_addon_fk", referencedColumnName = "id_addon")},
inverseJoinColumns = {
#JoinColumn(name = "id_car_fk", referencedColumnName = "id_car")})
to both side
just reverse the joinColumns and inverseJoinColumns
Try adding (fetch = FetchType.EAGER) to your ManyToMany annotation

Categories