Spring Data JPA child entity missing parent ID after transitive save - java

I have the following class structure
#Entity
#Data // lombok
public class Entity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "entity_details_id", referencedColumnName = "id")
#JsonManagedReference(value = "entityDetails")
private EntityDetails entityDetails;
}
#Entity
#Data
public class EntityDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(mappedBy = "entityDetails")
#JsonBackReference(value = "entityDetails")
private Entity entity;
// Some more fields
#OneToMany(mappedBy = "entityDetails", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonManagedReference(value = "childEntityDetails")
private List<Child> childList;
}
#Entity
#Data
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "description")
private String description;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "entity_details_id")
#JsonBackReference(value = "childEntityDetails)
private EntityDetails entityDetails;
}
Assume I have an Entity object with the following structure:
Entity{
id: null,
entityDetails: {
id: null,
childList: [
{ id: null, description: "ch1" },
{ id: null, description: "ch2" }
]
}
}
When I call entityRepository.save(entity), all the objects are persisted, but the Child table does not have a value for entity_details_id. The other values are correct (I do have Entity.entity_details_id correctly set), but this one does not work. I'm not sure if I'm missing something or if I'm just doing it wrong.

Related

Hibernate Criteria Api with Inner Join and Many to Many

I'm new with Hibernate and Criteria Query.
How can I implement it with Hibernate Criteria Object?
SELECT stateslocalization.StateId, stateslocalization.localization AS name
FROM processstate
Join states ON states.id = processstate.StateId
JOIN stateslocalization ON stateslocalization.StateId = states.id
WHERE processstate.ProcessId = 38 and processstate.StateId = states.id AND stateslocalization.StateId = states.id
Entities:
Process:
#Entity
#Table(name = "processes")
public class Process {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
#JoinTable(
name = "processstate",
joinColumns = {#JoinColumn(name = "ProcessId")},
inverseJoinColumns = {#JoinColumn(name = "StateId")}
)
private Set<State> states;
//getters and setters.....
}
State:
#Entity
#Table(name = "states")
public class State {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
private String name;
#ManyToMany(mappedBy = "states", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
private Set<Process> processes;
#OneToOne(mappedBy = "state")
private StateLocalization stateLocalization;
//getters and setters.....
}
StateLocalization:
#Entity
#Table(name = "stateslocalization")
public class StateLocalization {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "StateId", referencedColumnName = "id")
private State state;
private String localization;
//getters and setters.....
}
I did it with native query but I don't know how I can implement it to Hibernate Criteria, because I don't have entity processstate (it's only table).

Repeated column in mapping for entity in #OneToOne unidirectional mapping

Consider the following database structure
I need to implement unidirectional one to one mapping like that (structure is simplified):
#Entity
#Table(name = "entity")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne
#JoinColumn(name = "customer_info", nullable = false)
private CustomerInfo customerInfo;
#OneToOne
#JoinColumn(name = "customer_credentials", nullable = false)
private CustomerCredentials customerCredentials;
// getter, setters etc
}
#Entity
#Table(name = "customer_info")
public class CustomerInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
// getter, setters etc
}
#Entity
#Table(name = "customer_credentials")
public class CustomerCredentials {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
// getter, setters etc
}
But somehow hibernate unable to differentiate that those joins are from different tables and throws such error:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.example.Customer column: customer_id (should be mapped with insert="false" update="false")
Important notice: I do not want to use #OneToOne(mappedBy = "customer") because I need cascade save functionality
You can use #JoinTable instead of #JoinColumn to solve your problem:
#Entity #Table(name = "entity") public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(cascade = CascadeType.ALL, targetEntity = CustomerInfo.class)
#JoinTable(name = "customer_info", inverseJoinColumns = {#JoinColumn(name = "customer_id", nullable = false)})
private CustomerInfo customerInfo;
#OneToOne(cascade = CascadeType.ALL, targetEntity = CustomerCredentials.class)
#JoinTable(name = "customer_credentials", inverseJoinColumns = {#JoinColumn(name = "customer_id", nullable = false)})
private CustomerCredentials customerCredentials;
// getter, setters etc }
#Entity #Table(name = "customer_info") public class CustomerInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
// getter, setters etc }
#Entity #Table(name = "customer_credentials") public class CustomerCredentials {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
// getter, setters etc }
You could change the cascade strategy to any strategy you need. I just left CascadeType.ALL there as an example.

How to handle duplicate data of child table that belongs to 1 of 2 parent table has many-to-many relationship

I have 2 tables called Product and Category with many-to-many relationship. And Product has a one-to-many relationship with Images table. I created a table Product_Category to link 2 table Product and Category together. My problem is when 1 product belongs to 1 category, it's just fine with 4 images of that product. But if 1 product belongs to 2 categories, i get 8 images instead of 4
This is image of problem
As you can see is's supposed to be _1 _2 _3 _4 instead _1 _1 _2 _2 ...
This is my entities class
ProductEntity
#Entity
#Table(name = "product")
public class ProductEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#Column(name = "price")
private double price;
#Column(name = "material")
private String material;
#ManyToOne
#JoinColumn(name="careId")
private ProductCareEntity productCare;
#OneToMany(mappedBy = "product", fetch = FetchType.EAGER)
private List<ImageEntity> images;
#OneToMany(mappedBy = "product", fetch = FetchType.EAGER)
private List<ProductCategoryEntity> productCategoryEntities;
#OneToMany(mappedBy = "product", fetch = FetchType.EAGER)
private List<OrderDetailEntity> orderDetailEntityList;
#OneToMany(mappedBy = "product", fetch = FetchType.EAGER,cascade=CascadeType.ALL)
private List<ProductSizeQuantityEntity> productSizeQuantities;
CategoryEntity
#Entity
#Table(name = "category")
public class CategoryEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#OneToMany(mappedBy = "category", fetch = FetchType.EAGER)
private List<ProductCategoryEntity> productCategories;
ProductCategoryEntity
#Entity
#Table(name = "product_category")
public class ProductCategoryEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#ManyToOne
#JoinColumn(name = "categoryId")
private CategoryEntity category;
#ManyToOne
#JoinColumn(name = "productId")
private ProductEntity product;
How can i solve this problem?
I don't think you need ProductCategoryEntity at all. All you need to do is to make a List of Category type in product and List of Product type in Category. like this:
#Entity
#Table(name = "product")
public class ProductEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#Column(name = "price")
private double price;
#Column(name = "material")
private String material;
#ManyToOne
#JoinColumn(name="careId")
private ProductCareEntity productCare;
#OneToMany(mappedBy = "product", fetch = FetchType.EAGER)
private List<ImageEntity> images;
#ManyToMany(cascade = { CascadeType.ALL })
#JoinTable(name = "ProductCategory",
joinColumns = { #JoinColumn(name = "category_id") },
inverseJoinColumns = { #JoinColumn(name = "product_id"))
private List<Category> categories;
#OneToMany(mappedBy = "product", fetch = FetchType.EAGER)
private List<OrderDetailEntity> orderDetailEntityList;
#OneToMany(mappedBy = "product", fetch =
FetchType.EAGER,cascade=CascadeType.ALL)
private List<ProductSizeQuantityEntity> productSizeQuantities;
and
#Entity
#Table(name = "category")
public class CategoryEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#ManyToMany(mappedBy = "projects")
#JoinTable(name = "ProductCategory")
private List<Product> products;

Set criteria on column in which data is saved as a string JSON

I have following entities:
public class **Product** implements Serializable {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Id_Gen")
private Long id;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
#Fetch(value=FetchMode.JOIN)
#JoinColumn(name = "PRODUCT_DETAILS_TABLE")
private ProductJsonDetails productJsonDetails;
}
#Table(name = "PRODUCT_DETAILS_TABLE")
public class **ProductJsonDetails** implements Serializable {
#Id
#Access(AccessType.PROPERTY)
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Id_Gen")
private Long id;
#JsonIgnore
#OneToOne(fetch = FetchType.LAZY, mappedBy = "productJsonDetails")
private Product product;
#JsonIgnore
#Column(name = "**XYZ_JSON**")
private String **detailsJson**;
}
}
column XyZ_JSON has string in below format
{"name" : "ABC","type":{"id" : "LMN", type : "CCC"}}
I want to set criteria as below:
DetachedCriteria criteria = DetachedCriteria.forClass(Product.class, "product");
criteria.createAlias("product.productJsonDetails", "productJsonDetails", JoinType.LEFT_OUTER_JOIN);
critera.add (Restrictions.eq("productJsonDetails.type.id","1")) - >>> This throws error.
How to set restriction on Id element of String json ???

Joining with cross-reference table in hibernate and spring

I use hibernate and spring-data. There are two tables with many-to-many relationship.
#Entity
#Table(name = "FirstEntity")
public class FirstEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "first_entity_id")
private Long id;
#Column(name = "first_entiry_name")
private String name;
/* getters and setters are below*/
}
#Entity
#Table(name = "SecondEntity")
public class SecondEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "second_entity_id")
private Long id;
#Column(name = "second_entiry_name")
private String name;
#Column(name = "second_entiry_desc")
private String description;
/* getters and setters are below*/
}
And entity for cross-reference table.
#Entity
#Table(name = "FirstSecondEntity")
public class FirstSecondEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "first_second_entity_id")
private Long id;
#Column(name = "first_entity_id")
private Long firstEntityId;
#Column(name = "second_entity_id")
private Long secondEntityId;
/* getters and setters are below*/
}
I need SELECT like this
SELECT FirstEntity.name, SecondEntity.name, SecondEntity.description FROM SecondEntity INNER JOIN FirstSecondEntity ON SecondEntity.id = FirstSecondEntity.secondEntityId INNER JOIN User ON FirstEntity.id = FirstSecondEntity.firstEntityId
i.e. I need all records from cross-reference table where instead of ids there is actual info from entities.
Inserting this query into #Query annotation in my CrudRepository-extended class doesn't work because of
ERROR [main][org.hibernate.hql.internal.ast.ErrorCounter] Path expected for join!
So I need your help.
Your join table is all screwed up. In this case, you actually don't even need the join table as a hibernate mapping:
In Second Entity add the following list:
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "FirstSecondEntity",
joinColumns = {
#JoinColumn(name = "first_entity_id",
nullable = false,
updatable = false) },
inverseJoinColumns = {
#JoinColumn(name = "second_entity_id",
nullable = false,
updatable = false) },
)
private List<FirstEntity> firstEntities;
In FirstEntity add the following list:
#ManyToMany(fetch = FetchType.LAZY,
mappedBy = "firstEntities")
private List<SecondEntity> secondEntities;

Categories

Resources