2

I have the following entity classes

public class Container {


    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private final Long id;

    @Column(name = "container_id")
    private final String containerId;

    @OneToMany(cascade = { CascadeType.ALL }, orphanRemoval = true, fetch = FetchType.EAGER)
    @JoinColumn(name = ContainerItem.container_id, referencedColumnName = "container_id", nullable = true)
    private Collection<ContainerItem> containerItems = Collections.emptyList();

}


public class ContainerItem {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private final Long id;

    @Column(name = "container_id")
    private String containerId;

    @OneToOne(targetEntity = Order.class)
    @NonNull
    private final Order order;
}


public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private final Long id;

    @Column(name = "order_id")
    private String orderId;

    @OneToMany(cascade = { CascadeType.ALL }, orphanRemoval = true, fetch = FetchType.EAGER)
    @JoinColumn(name = Product."order_id", referencedColumnName = "order_id")
    private Collection<Product> products;

}


public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private final Long id;


    @Column(name = "order_id")
    private String orderId;

    @Column(name = "text")
    private final String text;
}

I have used random names for objects to keep it simple. (Edited to resemble a fictional real-world scenario to give some meaning to it.

Basically, there are two main operations -

  1. I execute CRUD operations for Order and Product and there are no issues here. When an Order is inserted/updated/deleted, the Product is also inserted/updated/deleted.

  2. I execute CRUD operations for Container and ContainerItem. For this to work successfully, there needs to be some Order that can be used by the ContainerItem in its foreign key (OneToOne mapping) that I specified (the column I use for the foreign key is the orderId in Order). I create them too, but I DO NOT want to create/update/delete the Order when I insert an Container which inserts a ContainerItem containing a mapping to the Order. How can I fix this?

At the same time, Order is not the rightful owner of ContainerItem and I do not want to have a mapping from the other table.

The save is performed as below with the entityManager.

public Long create(Container container) {
    this.entityManager.persist(container);
    this.entityManager.flush();
    return container.getId();
}

With the above entity mapping, I see an error as below, which I sort of understand, but do not know how to resolve.

During synchronization a new object was found through a relationship that was not marked cascade PERSIST: Order (id:null, orderId: "1", products: [])

The object received here is correct, I do not want to store/update/delete the state of Order or Product. How can I specify this unidirectional relation here?

Adarsh
  • 33
  • 8
  • It would be helpful to know more about what you're trying to express and/or the problem you're trying to solve. This may be an x-y problem. Is it your intention to represent a hierarchical data in RDBMS tables? Is it your intention to have a superclass/subclass relationship in your object model (if so, it isn't expressed in your code)? – scottb Nov 19 '21 at 16:15
  • there is no superclass/subclass relationship. A parent/child relationship exists across the data entities. – Adarsh Nov 19 '21 at 16:23
  • Tried to make it a little more understable with a real world (fictional) example – Adarsh Nov 19 '21 at 16:46
  • Can you explain a bit more on what is happening, and what you want to happen? When you insert a new container, how do you associate it to an existing Order? Where does this Order instance come from? Try reading it from the EntityManager context before setting this relationship on the ContainerItem to be persisted (or merged) – Chris Nov 19 '21 at 20:27
  • It will help us if you write a sample of code that generates de exception. It's great to have the entities, thanks, but it's not enough. A minimal reproducible example would include the code that generates de exception. – gmanjon Nov 20 '21 at 01:57
  • @Chris - let's just say that the Order and Product details are inserted through some master data. The Container and ContainerItem are also inserted in a similar fashion from some master data. The only check we need to make is that the ContainerItem contains an Order that exists (via the foreign key). Also, when Order is deleted, the ContainerItem containing this order should be deleted – Adarsh Nov 22 '21 at 08:39
  • 1
    @gmanjon - Edited to add code that contains a save/persist – Adarsh Nov 22 '21 at 08:43
  • `ContainerItem` and `Item` are the same right? The Collection in `Container` is defined for `Item`, but the name of the class is `ContainerItem` – gmanjon Nov 22 '21 at 08:55
  • yup, that was a typo. I fixed it – Adarsh Nov 22 '21 at 09:12
  • Sorry, didn't understand the question properly. I deleted the answer. See if this post can help you https://stackoverflow.com/questions/14618486/jpa-manytomany-transient-collection – gmanjon Nov 22 '21 at 11:11
  • JPA does not allow managed entities to reference non-managed entities - you are going to get an error or problems. Your app should do the check to make sure Order exists, by looking up the existing entity and use that reference in your new ones. That is the only way for providers to know about the instance referenced and what to really do with it (which is nothing unless you change something in it). Alternatively, you can not map this reference - make it read only, and control the foreign key through a basic mapping yourself. This would allow you to set the FK value directly. – Chris Nov 22 '21 at 15:51

0 Answers0