jpa OneToMany / ManyToOne how to save data - jpa

I'm learnig jpa and have a general question to saving data.
Suppose we have two entities:
Parent entity: Person
#JsonIgnore
#OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Car> cars = new HashSet<Car>();
Child entity: Car
#ManyToOne(fetch = FetchType.EAGER)
#JoinTable(name = "customer_car", joinColumns = #JoinColumn(name = "car_id"),
inverseJoinColumns = #JoinColumn(name = "person_id"))
private Person person;
The question is: What is the correct way to save data:
Person-Controller: I should use a #PostMapping to post a person with many cars.
Car-Controller: I should use a #PostMapping to post a car with many persons.
Option 1 and option 2 are possible

Related

Using Named Entity Graphs in Eclipselink not work

I have 2 classes
Collections
#Entity
#NamedEntityGraph(
name = "cars-graph",
attributeNodes = #NamedAttributeNode("cars"))
public class Collections {
#Id
#ReturnInsert(returnOnly=true)
private Long id;
#ManyToMany(cascade = ALL)
#JoinTable(name="CarsCollections",
joinColumns= #JoinColumn(name="COLLECTIONS_ID", referencedColumnName="ID"),
inverseJoinColumns=
{#JoinColumn(name = "MODELSRANGE_ID", referencedColumnName = "MODELSRANGE_ID"),
#JoinColumn(name = "MODELS_ID", referencedColumnName = "MODELS_ID"),
#JoinColumn(name = "TYPES_ID", referencedColumnName = "TYPES_ID")
}
)
public List<Cars> cars;
and Cars
#Entity(name = "Cars")
public class Cars {
#EmbeddedId
private CarsId id;
#ManyToOne(fetch = FetchType.EAGER)
#MapsId("modelsRangeid")
#JoinColumn(name = "MODELSRANGE_ID")
private ModelsRange modelsrange;
#ManyToOne(fetch = FetchType.EAGER)
#MapsId("modelsid")
#JoinColumn(name = "MODELS_ID")
private Models models;
#ManyToOne(fetch = FetchType.EAGER)
#MapsId("typesid")
#JoinColumn(name = "TYPES_ID")
private Types types;
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
#JoinColumn(name = "MAKE")
private Makes makes;
When i try to get Collections with Cars
EntityGraph entityGraph = em.getEntityGraph("cars-graph");
Collections collections = em.createQuery("select r from Collections r where r.id = :id", Collections.class)
.setParameter("id", 1L)
.setHint("javax.persistence.fetchgraph", entityGraph)
.getSingleResult();
System.out.println(collections.getCars());
I get {IndirectList: not instantiated}. Does not give errors, but Cars does not load.
If you add to the Collections entity for the Cars field "EAGER"
...
#ManyToMany(cascade = ALL, fetch = FetchType.EAGER)
#JoinTable(name="CarsCollections",
...
It works.
But then Cars will always load.
I use Jakarta EE9 and Eclipselink
Problem in javax name. In Jakarta EE need to use:
...
.setHint("jakarta.persistence.loadgraph", entityGraph)
...

JPA foreign key without entity

I'm trying to create a favorites table between a user and a business, but I don't want to use the entire entity, just the ids, how can this be done in JPA? Something like this:
#Data
#Entity
#Table(name = "favorite", schema = "public" , uniqueConstraints = {
#UniqueConstraint(columnNames = {"user_id", "business_id"})
})
public class Favorite {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "appuser_id")
#NotNull
private UUID appuser_id;
#Column(name = "business_id")
#NotNull
private Long businessId;
}
instead of:
#Data
#Entity
#Table(name = "favorite", schema = "public" , uniqueConstraints = {
#UniqueConstraint(columnNames = {"user_id", "business_id"})
})
public class Favorite {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "appuser_id", referencedColumnName="id")
private AppUser appUser;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "business_id", referencedColumnName="id")
private Business business;
}
Problem is, solution #1 has no foreign key ref of any kind, is there a way to do this? I would really prefer my result objects to only have ids and not the entire user / business entities every time.
I know I can make a dto with ids only and manually set it up / workaround, but I'd like an answer to this problem if one exists.

detached entity passed to persist: A class with ManyToOne relation to 2 more classes

Comment class
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "user_id")
private User user;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "image_id")
private Image image;
User class
#OneToMany(mappedBy = "user", cascade = CascadeType.MERGE, fetch =
FetchType.EAGER)
private List<Comment> comments = new ArrayList<>();
Image class
#OneToMany(mappedBy = "image",cascade = CascadeType.MERGE,fetch =
FetchType.EAGER)
private List<Comment> comments = new ArrayList<Comment>();
These are the ManyToOne and OneToMany relations I have. I am unable to persist the Comment object due to "detached entity passed to persist: ImageHoster.model.Comment" error.
I kind of figured out the issue. In the CommentRepository class where I am persisting the Comment object, I used .merge instead of .persist
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
try{
transaction.begin();
em.merge(newComment);
instead of em.persist(newComment);

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 :)

data not saved on join table

I generated entities using NetBeans (EclipseLink JPA) based on the following diagram:
The relevant generated code is:
Course
#JoinTable(name = "course_software", joinColumns = {
#JoinColumn(name = "course_id", referencedColumnName = "id", nullable = false)}, inverseJoinColumns = {
#JoinColumn(name = "software_id", referencedColumnName = "id", nullable = false)})
#ManyToMany
private List<Software> softwareList;
Software
#ManyToMany(mappedBy = "softwareList")
private List<Course> courseList;
The problem is with Course entity. When I try to persist it as follows
getFacade().create(currentCourse);
currentCourse.setSoftwareList(selectedSoftware);
then a record is created in course, but nothing is created in course_software join table.
How is this caused and how can I solve it?
It seems you don't need to specify the referencedColumnName attributes of #JoinColumn annotations as long as the columns referenced in the joined table are already primary keys.