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/
Related
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.
I am trying to implement a tree referencing itself (same class) with CRUD operations using Java and Hibernate. My class is :
#Entity
#Table(name="Person")
public class Person implements Comparable<Person>{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
#ManyToOne(cascade = {CascadeType.ALL})
private Person father;
#OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
private List<Person> children = new ArrayList<Person>();
}
Insertion works good, at each insertion I set person's father to person and add person to father's children. While deleting, if I delete the person, it complains that person id is referenced by father, if I delete father, it complains that father id is referenced by person. So, what is the correct procedure of deleting or updating? There are similar questions, but I can not find the exact explanation for this bidirectional referencing problem.
So, I have found a solution to the problem thanks to #Al1's mapped byannotation. Still, after that I could not retrieve objects due to LazyInitializationException , but was able to delete the Leafs in a tree.
I have fixed that issue by changing private List<Person> children= new ArrayList<Person>(); to private Collection<Person> children = new LinkedHashSet<Person>();
The class now looks like:
public class Person implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
#ManyToOne(cascade = {CascadeType.ALL})
private Person father;
#OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, mappedBy= "father")
private Collection<Person> children = new LinkedHashSet<Person>();
}
In order to delete the tree node, I had to to load the children by Hibernate.initialize(this.getChildren()); and then recursively delete every node. My function for deletion:
public static String deletePerson(Person p){
Transaction trns = null;
Session session = HibernateUtil.buildSessionFactory().openSession();
try {
trns = session.beginTransaction();
Hibernate.initialize(p.getChildren());
if (p.hasChildren()){
Collection<Person> children = p.getChildren();
for (Person person : children) {
deletePerson(person);
}
String hql = "delete from Person where name = :name";
session.createQuery(hql).setString("name", p.getName()).executeUpdate();
session.getTransaction().commit();
return "success";
}
else {
String hql = "delete from Person where name = :name";
session.createQuery(hql).setString("name", p.getName()).executeUpdate();
session.getTransaction().commit();
return "success";
}
} catch (RuntimeException e) {
if (trns != null) {
trns.rollback();
}
e.printStackTrace();
} finally {
session.flush();
session.close();
}
return "failure";
}
Hope this helps somebody who works with Hibernate and trees:)
I have an EJB many-to-many (bi-directional) relation between classes (entity-classes) Person and Hobby. There are corresponding tables in the database, called PERSON and HOBBY, as well as a table PERSON_HOBBY for the many-to-many relationship.
As I will detail below, the problem is that whenever I try to persist a person with hobbies, I run into a Foreign Key constraint violation. This is because the entityManager tries to save new rows into PERSON_HOBBY that contain references to a person-entity with ID=0, which doesn’t exist in the PERSON table. I’ll come back to that later, but first I’ll show the relevant parts of the entity classes.
First, here is entity class Person:
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private String email;
#ManyToMany(cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER)
/* Note: I used to have CascadeType.PERSIST in the above line as well, but
it caused "Detached object passed to persist" exceptions whenever I tried to
persist a person with hobbies. So I suppose I was right in deleting
CascadeType.PERSIST...? */
#JoinTable(name = "PERSON_HOBBY",
joinColumns = #JoinColumn(name="personId", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="hobbyId", referencedColumnName="id"))
private List<Hobby> hobbies = new ArrayList<Hobby>();
public List<Hobby> getHobbies () {
return hobbies;
}
public void setHobbies (List<Hobby> hobbies) {
this.hobbies = hobbies;
for(Hobby h:hobbies) { // this is to maintain bi-directionality
h.addPerson(this);
}
}
// other getters and setters omitted here.
Then entity class Hobby:
#Entity
public class Hobby {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(nullable = false)
private String description;
#ManyToMany(mappedBy = "hobbies", fetch = FetchType.EAGER)
private List<Person> persons;
public Hobby() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
// getter and setter for Description omitted here.
public List<Person> getPersons () {
return persons;
}
public void setPersons (List<Person> persons) {
this.persons = persons;
}
public void addPerson (Person p) {
this.persons.add(p);
}
}
I also have a stateless session bean, that’s shown here as far as relevant to the issue:
#Stateless
#Default
public class PersonRepositoryImpl implements PersonRepository {
#PersistenceContext
private EntityManager entityManager;
#Override
public Person create(Person p) {
entityManager.persist(p);
entityManager.flush();
return p;
}
#Override
public Person createPersonWithHobbies(Person p, List<Hobby>hobbyLijst) {
p = create(p); // I've also tried simply: create(p);
System.out.println("The newly assigned ID for the persisted
person is: " + p.getId());
// That last line **always** prints the person-ID as being 0 !!!!
p.setHobbies(hobbyLijst);
entityManager.merge(p); // This should save/persist the person's hobby's!
entityManager.flush();
return p;
}
}
Now from my servlet, I've been trying in two different ways. First, I tried calling method create(p) on the above session bean. That is, after creating a new Person instance p, setting all its non-relational fields, AND calling setHobbies on it (with a non-zero list of Hobby objects taken from the database), I called:
personRepo.create(p);
But this resulted in the Foreign Key (FK) exception:
INSERT on table 'PERSON_HOBBY' caused a violation of foreign key
constraint 'FK_EQAEPVYK583YDWLXC63YB3CXK' for key (0). The statement
has been rolled back.”
The FK-constraint mentioned here is the one in PERSON_HOBBY referring to PERSON.
The second way I tried was to make the following call from the servlet:
personRepo.createPersonWithHobbies(p, hobbyLijst);
where, just like before, p is the new person object; and hobbyLijst is that person's list of hobbies. And this resulted in the exact same FK-exception as the earlier call to personRepo.create(p).
Importantly, the println statement within method createPersonWithHobbies, calling getId() on the newly persisted person-object, ALWAYS gives that object's ID as being 0. Which I suppose does explain the FK-exception, since there's no person entity/row in the PERSON table with an ID of 0, nor is there supposed to be one. But of course the getId() call should not output 0. Instead, it should output the newly generated ID of the newly persisted person entity. (And yes, it IS persisted correctly in the PERSON tabel, with a correctly generated ID>0. So the correct ID is there in the PERSON-table - it just seems to be invisible to the entityManager and/or the container.)
Thanks.
I have a hibernate entity with one-to-many association:
#Entity
public class Parent {
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
#Cascade(CascadeType.ALL)
private Set<Child> children = new HashSet<Child>();
#Version
private Date version;
}
#Entity
public class Child {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PARENT_ID")
private Parent parent;
#Basic
private String key;
}
*some annotations removed for clarity
Child entity maps on a table with composite primary key (KEY and PARENT_ID). The problem is when two users adds the same Child (with the same key) to the same Parent the cascade save (session.saveOrUpdate(parent)) fails with Child's primary key violation instead of optimistic lock failure.
If users change some other property in the Parent entity in addition to the collection, the optimistic lock works fine.
I could add some fictive property to the Parent class and change it every time when the collection changes and it will do the trick but it looks like a hack.
Or I could replace composite primary key to a surrogate one (by adding #Id).
The question is: What is the recommended approach of implementing optimistic locking in such a case?
Could be related to Hibernate #Version causing database foreign key constraint failure.
Only unidirectional collection changes are going to be propagated to the parent entity version. Because you are using a bidirectional association, it's the #ManyToOne side that will control this association, so adding/removing an entity in the parent-side collection is not going to affect the parent entity version.
However, you can still propagate changes from child entities to parent entities. This requires you to propagate the OPTIMISTIC_FORCE_INCREMENT lock whenever the child entity is modified.
In short, you need to have all your entities implementing a RootAware interface:
public interface RootAware<T> {
T root();
}
#Entity(name = "Post")
#Table(name = "post")
public class Post {
#Id
private Long id;
private String title;
#Version
private int version;
//Getters and setters omitted for brevity
}
#Entity(name = "PostComment")
#Table(name = "post_comment")
public class PostComment
implements RootAware<Post> {
#Id
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
private Post post;
private String review;
//Getters and setters omitted for brevity
#Override
public Post root() {
return post;
}
}
#Entity(name = "PostCommentDetails")
#Table(name = "post_comment_details")
public class PostCommentDetails
implements RootAware<Post> {
#Id
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId
private PostComment comment;
private int votes;
//Getters and setters omitted for brevity
#Override
public Post root() {
return comment.getPost();
}
}
Then, you need two event listeners:
public static class RootAwareInsertEventListener
implements PersistEventListener {
private static final Logger LOGGER =
LoggerFactory.getLogger(RootAwareInsertEventListener.class);
public static final RootAwareInsertEventListener INSTANCE =
new RootAwareInsertEventListener();
#Override
public void onPersist(PersistEvent event) throws HibernateException {
final Object entity = event.getObject();
if(entity instanceof RootAware) {
RootAware rootAware = (RootAware) entity;
Object root = rootAware.root();
event.getSession().lock(root, LockMode.OPTIMISTIC_FORCE_INCREMENT);
LOGGER.info("Incrementing {} entity version because a {} child entity has been inserted", root, entity);
}
}
#Override
public void onPersist(PersistEvent event, Map createdAlready)
throws HibernateException {
onPersist(event);
}
}
and
public static class RootAwareInsertEventListener
implements PersistEventListener {
private static final Logger LOGGER =
LoggerFactory.getLogger(RootAwareInsertEventListener.class);
public static final RootAwareInsertEventListener INSTANCE =
new RootAwareInsertEventListener();
#Override
public void onPersist(PersistEvent event) throws HibernateException {
final Object entity = event.getObject();
if(entity instanceof RootAware) {
RootAware rootAware = (RootAware) entity;
Object root = rootAware.root();
event.getSession().lock(root, LockMode.OPTIMISTIC_FORCE_INCREMENT);
LOGGER.info("Incrementing {} entity version because a {} child entity has been inserted", root, entity);
}
}
#Override
public void onPersist(PersistEvent event, Map createdAlready)
throws HibernateException {
onPersist(event);
}
}
which you can register as follows:
public class RootAwareEventListenerIntegrator
implements org.hibernate.integrator.spi.Integrator {
public static final RootAwareEventListenerIntegrator INSTANCE =
new RootAwareEventListenerIntegrator();
#Override
public void integrate(
Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
final EventListenerRegistry eventListenerRegistry =
serviceRegistry.getService( EventListenerRegistry.class );
eventListenerRegistry.appendListeners(EventType.PERSIST, RootAwareInsertEventListener.INSTANCE);
eventListenerRegistry.appendListeners(EventType.FLUSH_ENTITY, RootAwareUpdateAndDeleteEventListener.INSTANCE);
}
#Override
public void disintegrate(
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
//Do nothing
}
}
and then supply the RootAwareFlushEntityEventListenerIntegrator via a Hibernate configuration property:
configuration.put(
"hibernate.integrator_provider",
(IntegratorProvider) () -> Collections.singletonList(
RootAwareEventListenerIntegrator.INSTANCE
)
);
Now, when you modify a PostCommentDetails entity:
PostCommentDetails postCommentDetails = entityManager.createQuery(
"select pcd " +
"from PostCommentDetails pcd " +
"join fetch pcd.comment pc " +
"join fetch pc.post p " +
"where pcd.id = :id", PostCommentDetails.class)
.setParameter("id", 2L)
.getSingleResult();
postCommentDetails.setVotes(15);
The parent Post entity version is modified as well:
SELECT pcd.comment_id AS comment_2_2_0_ ,
pc.id AS id1_1_1_ ,
p.id AS id1_0_2_ ,
pcd.votes AS votes1_2_0_ ,
pc.post_id AS post_id3_1_1_ ,
pc.review AS review2_1_1_ ,
p.title AS title2_0_2_ ,
p.version AS version3_0_2_
FROM post_comment_details pcd
INNER JOIN post_comment pc ON pcd.comment_id = pc.id
INNER JOIN post p ON pc.post_id = p.id
WHERE pcd.comment_id = 2
UPDATE post_comment_details
SET votes = 15
WHERE comment_id = 2
UPDATE post
SET version = 1
where id = 1 AND version = 0
For me it was enough to set the OptimisticLock annotation:
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
#OptimisticLock(excluded = false)
private Set<Child> children = new HashSet<Child>();
First I think you need to declare your primary key and define how the PK is generated.
Example :
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
Then, the best way to add new child to your parent should be like this (on the parent side):
public Child addChild() {
Child child = new Child()
if (childList== null) {
childList= new ArrayList<childList>();
}
child.setparent(this);
childList.add(child);
return child;
}
When the child already exist, simply do the same but without creating a new Child.
I think it should resolve some of your problems.
Config
EcliplseLink 2.3.2
JPA 2.0
The entities are auto created from the db schema from netbeans with Entity Classes from Database... wizard.
The controller classes are auto created from netbeans with JPA Controller Classes from Entity Classes... wizard
Short version of question
In a classic scenario, two tables with one to many relation. I create the parent entity, then the child entity and I attach the child to the parent's collection. When I create (controller method) the parent entity, I expect the child entity to be created to and associated with parent. Why doesn't it happen?
Long version
Parent class
#Entity
#XmlRootElement
public class Device implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
private Integer id;
#Column(unique=true)
private String name;
#Temporal(TemporalType.TIMESTAMP)
private Date updated;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "deviceId")
private Collection<NetworkInterface> networkInterfaceCollection;
public Device() {
}
public Device(String name) {
this.name = name;
updated = new Date();
}
// setters and getters...
#XmlTransient
public Collection<NetworkInterface> getNetworkInterfaceCollection() {
return networkInterfaceCollection;
}
public void setNetworkInterfaceCollection(Collection<NetworkInterface> networkInterfaceCollection) {
this.networkInterfaceCollection = networkInterfaceCollection;
}
public void addNetworkInterface(NetworkInterface net) {
this.networkInterfaceCollection.add(net);
}
public void removeNetworkInterface(NetworkInterface net) {
this.networkInterfaceCollection.remove(net);
}
// other methods
}
Child class
#Entity
#Table(name = "NETWORK_INTERFACE")
#XmlRootElement
public class NetworkInterface implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
private Integer id;
private String name;
#Temporal(TemporalType.TIMESTAMP)
private Date updated;
#JoinColumn(name = "DEVICE_ID", referencedColumnName = "ID")
#ManyToOne(optional = false)
private Device deviceId;
public NetworkInterface() {
}
public NetworkInterface(String name) {
this.name = name;
this.updated = new Date();
}
// setter and getter methods...
public Device getDeviceId() {
return deviceId;
}
public void setDeviceId(Device deviceId) {
this.deviceId = deviceId;
}
}
Main class
public class Main {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("wifi-dbPU");
DeviceJpaController deviceController = new DeviceJpaController(emf);
NetworkInterfaceJpaController netController = new NetworkInterfaceJpaController(emf);
Device device = new Device("laptop");
NetworkInterface net = new NetworkInterface("eth0");
device.getNetworkInterfaceCollection().add(net);
deviceController.create(device);
}
}
This class throws a NullPointerException in line: device.getNetworkInterfaceCollection().add(net);
The system knows that there is a new entity device and it has an element net in it's collection. I expected it to write device in db, get device's id, attach it to net and write it in db.
Instead of this, I found that these are the steps I have to do:
deviceController.create(device);
net.setDeviceId(device);
device.getNetworkInterfaceCollection().add(net);
netController.create(net);
Why do I have to create the child when the parent class knows it's child and it should create it for me?
The create method from DeviceJpaController (sorry for the long names in fields, they are auto generated).
public EntityManager getEntityManager() {
return emf.createEntityManager();
}
public void create(Device device) {
if (device.getNetworkInterfaceCollection() == null) {
device.setNetworkInterfaceCollection(new ArrayList<NetworkInterface>());
}
EntityManager em = null;
try {
em = getEntityManager();
em.getTransaction().begin();
Collection<NetworkInterface> attachedNetworkInterfaceCollection = new ArrayList<NetworkInterface>();
for (NetworkInterface networkInterfaceCollectionNetworkInterfaceToAttach : device.getNetworkInterfaceCollection()) {
networkInterfaceCollectionNetworkInterfaceToAttach = em.getReference(networkInterfaceCollectionNetworkInterfaceToAttach.getClass(), networkInterfaceCollectionNetworkInterfaceToAttach.getId());
attachedNetworkInterfaceCollection.add(networkInterfaceCollectionNetworkInterfaceToAttach);
}
device.setNetworkInterfaceCollection(attachedNetworkInterfaceCollection);
em.persist(device);
for (NetworkInterface networkInterfaceCollectionNetworkInterface : device.getNetworkInterfaceCollection()) {
Device oldDeviceIdOfNetworkInterfaceCollectionNetworkInterface = networkInterfaceCollectionNetworkInterface.getDeviceId();
networkInterfaceCollectionNetworkInterface.setDeviceId(device);
networkInterfaceCollectionNetworkInterface = em.merge(networkInterfaceCollectionNetworkInterface);
if (oldDeviceIdOfNetworkInterfaceCollectionNetworkInterface != null) {
oldDeviceIdOfNetworkInterfaceCollectionNetworkInterface.getNetworkInterfaceCollection().remove(networkInterfaceCollectionNetworkInterface);
oldDeviceIdOfNetworkInterfaceCollectionNetworkInterface = em.merge(oldDeviceIdOfNetworkInterfaceCollectionNetworkInterface);
}
}
em.getTransaction().commit();
} finally {
if (em != null) {
em.close();
}
}
}
I finally understood the logic behind persisting one to many entities. The process is:
Create parent class
Persist it
Create child class
Associate child with parent
Persist child (the parent collection is updated)
With code:
public class Main {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("wifi-dbPU");
DeviceJpaController deviceController = new DeviceJpaController(emf);
NetworkInterfaceJpaController netController = new NetworkInterfaceJpaController(emf);
Device device = new Device("laptop"); // 1
deviceController.create(device); // 2
NetworkInterface net = new NetworkInterface("eth0"); // 3
net.setDeviceId(device.getId()); // 4
netController.create(net); // 5
// The parent collection is updated by the above create
}
}
Now, I can find a device (with id for example) and I can get all its children using
Collection<NetworkInterface> netCollection = device.getNetworkInterfaceCollection()
In the device entity class, which I posted in the question, there is no need for the methods addNetworkInterface and removeNetwokrInterface.
#Dima K is correct in what they say. When you do this:
Device device = new Device("laptop");
NetworkInterface net = new NetworkInterface("eth0");
device.getNetworkInterfaceCollection().add(net);
deviceController.create(device);
The collection in device hasn't been initialized and so you get a NPE when trying to add to it. In your Device class, when declaring your Collection, you can also initialize it:
private Collection<NetworkInterface> networkInterfaceCollection = new CollectionType<>();
As for persisting, your assumptions are correct but I think the execution is wrong. When you create your device, make it persistent with JPA right away (doing transaction management wherever needed).
Device device = new Device("laptop");
getEntityManager().persist(device);
Do the same for the NetworkInterface:
NetworkInterface net = new NetworkInterface("eth0");
getEntityManager().persist(net);
Now since both your entities are persisted, you can add one to the other.
device.getNetworkInterfaceCollection().add(net);
JPA should take care of the rest without you having to call any other persists.
This is a known behavior of collection data members.
The easiest solution is to modify your collection getter to lazily create the collection.
#XmlTransient
public Collection<NetworkInterface> getNetworkInterfaceCollection() {
if (networkInterfaceCollection == null) {
networkInterfaceCollection = new Some_Collection_Type<NetworkInterface>();
}
return networkInterfaceCollection;
}
Also, remember to refer to this data member only through the getter method.
This exception means you're trying to locate an entity (probably by em.getReference()) that hasn't been persisted yet.
You cannot you em.getReference() or em.find() on entities which still don't have a PK.
In order to enable save ability on a #OneToMany relation e.g.
#OneToMany(mappedBy="myTable", cascade=CascadeType.ALL)
private List<item> items;
Then you have to tell to your #ManyToOne relation that it is allowed to update myTable like this updatable = true
#ManyToOne #JoinColumn(name="fk_myTable", nullable = false, updatable = true, insertable = true)