JPA Self Join using JoinTable - spring

I have 1 entity call Item in which I want to be able to link parent items to children. to use a join table to create a parent/child relationship. I haven't been able to get any good documentation on. So if anyone has any thoughts I'm all ears.
Here is what I have... which works most of the time.
public class Item implements java.io.Serializable {
#Id
private Long id;
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinTable(name = "ITEMTOITEM", joinColumns = { #JoinColumn(name = "ITEMID") }, inverseJoinColumns = { #JoinColumn(name = "PARENTITEMID") } )
private Item parent;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<Item> children;
}
At times when I want to bring back objects that are tied to this item table I am getting an error of the following:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.webflow.engine.ActionExecutionException: Exception thrown executing [AnnotatedAction#6669ff5 targetAction = com.assisted.movein.web.common.nav.NavAction#6edf74b7, attributes = map['method' -> 'handleEntry']] in state 'oneTimeChargesAndFeesView' of flow 'in-flow' -- action execution attributes were 'map['method' -> 'handleEntry']'; nested exception is Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.0.1 (Build b04-fcs (04/11/2008))): oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: ORA-00904: "PARENTITEM_ITEMID": invalid identifier
Error Code: 904
Call: SELECT ITEMID, ITEMSHORTDESC, EFFENDDATE, ITEMDESC, PARENTITEM_ITEMID, ITEMTYPECODE FROM ITEM WHERE (ITEMID = ?)
bind => [1250]
Query: ReadObjectQuery(com.domain.Item)
Any help would be appreciated.

Try to use #JoinColumninstead:
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinColumn(name = "PARENTITEMID", referencedColumnName = "ITEMID")
private Item parent;
#OneToMany(
cascade = {CascadeType.ALL},
orphanRemoval = true,
fetch = FetchType.LAZY
)
#JoinColumn(name = "PARENTITEMID")
private List<Item> children;

After a lot of reading on JPA 2.0 I figured out that I needed a newer version of Eclipselink 2.3+ in order to support what I was trying to do. Here is the code that actually worked in my case, but it will not work due to our dependency on an older version [EclipseLink 2.0.2]. Also another project's is still using Toplink-essentials JPA 1.0 which again does like this notation.
public class Item {
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinTable(name = "ITEMINCENTIVESMAPPING",
joinColumns = { #JoinColumn(name = "INCENTIVEITEMID", referencedColumnName = "ITEMID", insertable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "ITEMID", referencedColumnName = "ITEMID", insertable = false, updatable = false) } )
private Item parentItem;
#OneToMany(fetch = FetchType.LAZY)
#JoinTable(name = "ITEMINCENTIVESMAPPING",
joinColumns = { #JoinColumn(name = "INCENTIVEITEMID", referencedColumnName = "ITEMID") },
inverseJoinColumns = { #JoinColumn(name = "ITEMID", referencedColumnName = "ITEMID") } )
private List<Item> items;
}

I believe #JoinTable is only allowed on a #OneToOne or #OneToMany or #ManyToMany, I don't think it makes any sense on a #ManyToOne. Use a #JoinColumn, or a #OneToOne.
Also your #OneToMany does not make sense, the mappedBy must be an attribute and you have no parentItem, it should be parent, and parent should use a #JoinColumn.

Related

Using nested property access in a JPA repository for composite key entity implemented using #EmbeddedID approach returning null values

My SQL view :-
CREATE OR REPLACE VIEW my_view
AS
SELECT
col1,
col2,
col3,
col4,
col5,
col6
FROM
my_table
My JPA entity :-
#Entity
#Table(name = "my_view")
#Getter
#Setter
public class MyEntity {
#EmbeddedId
private MyPk myPk;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "col1", insertable = false, updatable = false)
private Entity1 entity1 ;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col2", insertable = false, updatable = false)
private Entity2 entity2;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col3", insertable = false, updatable = false)
private Entity3 entity3;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col4", insertable = false, updatable = false)
private Entity4 entity4;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col5", insertable = false, updatable = false)
private Entity5 entity5;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col6", insertable = false, updatable = false)
private Entity6 entity6;
}
My Embedded Id class:-
#NoArgsConstructor
#EqualsAndHashCode
#AllArgsConstructor
#Embeddable
public class MyPk implements Serializable {
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "col1", insertable = false, updatable = false)
private Entity1 entity1 ;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col2", insertable = false, updatable = false)
private Entity2 entity2;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col3", insertable = false, updatable = false)
private Entity3 entity3;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col4", insertable = false, updatable = false)
private Entity4 entity4;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col5", insertable = false, updatable = false)
private Entity5 entity5;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col6", insertable = false, updatable = false)
private Entity6 entity6;
}
My JPA Repository :-
public interface MyEntityRepository extends JpaRepository<MyEntity, MyPk> {
List<MyEntity> findByMyPk_Entity1_Id(Long id);
}
Entity1 has an attribute id
I have tried #IdClass approach for composite key and many other solutions related to composite key but all are giving me some kind of error during runtime
This above approach is giving me no runtime error but giving null elements when invoking findByMyPk_Entity1_Id method but its giving correct count of elements in list
I cant use any kind of sequence from table or any other unique column approach dur to my underlying code. Also I tried using #mapIds approach but its also giving null elements.
For some reason JPA repository is not able to convert into entities but its able to give correct count of entities fetched
Also when using findAll method of repository in debugger its giving me proper entities list with no null elements but when searching through nested property i am not able to get entities
spring-data-jpa:1.9.4 version
hibernate-jpa-2.1-api:1.0.0
java 8
< Its a legacy project :") >
I don't know what you really have mapped in your table/view that you really need all 6 columns to uniquely identify a row. Assuming you do, and assuming they are all references to other tables that you want to have mapped in your entity, there are a number of approaches. The easiest, IMO more flexible approach might be this:
#Entity
#Table(name = "my_view")
public class MyEntity {
#EmbeddedId
private MyPk myPk;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "col1")
#MapsId("entity1")
private Entity1 entity1 ;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col2")
#MapsId("entity1")
private Entity2 entity2;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col3")
#MapsId("entity1")
private Entity3 entity3;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col4")
#MapsId("entity1")
private Entity4 entity4;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col5")
#MapsId("entity1")
private Entity5 entity5;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "col6")
#MapsId("entity1")
private Entity6 entity6;
}
#Embeddable
public class MyPk implements Serializable {
private Integer entity1 ;//use the ID type from Entity1's primary key
private Integer entity2;
private Integer entity3;
private Integer entity4;
private Integer entity5;
private Integer entity6;
}
Mappings in the MyPk embeddable class will be basic mappings, and pick up the column name settings from the entity ManyToOne mappings. Should you try to ever write one out (you can't write to views, but JPA treats everything as a table), you only need to set the appropriate relationships and JPA will extract the fk values to populate your MyEntity.myKey.entityX values for you.
Having both the embedded and the ManyToOne references means you can have the fk values within your entity and accessible without having to fetch the related entity just for the ID value.

Query result Infinite Recursion on ManyToMany relationship on hibernate

I have a entity mapping like this:
As you can see it is the bidirectional relationship and the team_users table has it own primary key and extra column - active.
Key code in team entity:
#OneToMany(mappedBy = "team", fetch = FetchType.LAZY)
private Set<TeamUsers> team_users = new HashSet<TeamUsers>();
Key code in user entity:
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private Set<TeamUsers> team_users = new HashSet<TeamUsers>();
Key code in team_user entity:
#ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "TEAM_ID")
private Team team;
#ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID")
private User user;
I have a API which will return all team information, then I have service class like:
#Autowired
private TeamRepository teamRepo;
public List<Team> listAll() {
return (List<Team>) teamRepo.findAll();
}
Then the chrome log me that I have a "undefined" value, and when I test it by postman it shows me the infinite loop value:
I want to figure out what is the best approach to fetch the data?
I want to all information that tells me the team situation, including team... users...active status , almost everthing.
Any suggestions?
update
I tried to use #JsonIgnore on intermidate table :
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "TEAM_ID")
private Team team;
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID")
private User user;
but I won't get user information in that case and it avoid infinite loop:
What else I can do to get all information for teams?

How to create Predicate BooleanExpression for many to many relations in QueryDSL

How can inner join be done on Many to Many relations using Predicate BooleanExpression?
I have 2 entities
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#ManyToMany(fetch = FetchType.LAZY,
cascade = { CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH, CascadeType.PERSIST})
#JoinTable(name = "a_b_maps",
joinColumns = #JoinColumn(name = "a_id", nullable =
false,referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "b_id", nullable = false,
referencedColumnName = "id")
)
private Set<B> listOfB = new HashSet<B>();
}
public class B {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#ManyToMany(fetch = FetchType.LAZY,
cascade = { CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH, CascadeType.PERSIST})
#JoinTable(name = "a_b_maps",
joinColumns = #JoinColumn(name = "b_id", nullable =
false,referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "a_id", nullable = false,
referencedColumnName = "id")
)
private Set<A> listOfA = new HashSet<A>();
}
A Base repo
#NoRepositoryBean
public interface BaseRepository<E, I extends Serializable>
extends JpaRepository<E, I> {
}
And a repository class for A
public interface Arepo extends BaseRepository<A, Integer>,
QueryDslPredicateExecutor<A> {
Page<A> findAll(Predicate predicate, Pageable pageRequest);
}
Now I want to use A Repo with Predicate query. I need to form a predicate where I can load A based on some given Bs
I tried
QA a = QA.a;
QB b = QB.b;
BooleanExpression boolQuery = null;
JPQLQuery<A> query = new JPAQuery<A>();
query.from(a).innerJoin(a.listOfB, b)
.where(b.id.in(someList));
Now I am able to form a JPQLQuery, but the repository expects a Predicate. How can I get Predicate from the JPQLQuery??
Or, how can the inner join be achieved using Predicate?
I am able to create a Predicate with the help of answer given here
https://stackoverflow.com/a/23092294/1969412.
SO, instead of using JPQLQuery, I am directly using
a.listOfB.any()
.id.in(list);
This is working like a charm.

Spring MVC - loading data from database

I have two entities which are in many to many relation and I can't load Set <Category> categories. These fields are filled in the database.
#Entity
#Table(name="Product")
public class Product {
#Id
#GeneratedValue
private int idProduct;
private String status;
private String name;
#ManyToMany(fetch = FetchType.EAGER, mappedBy= "products")
private Set <Category> categories;
}
#Entity
#Table(name="Category")
public class Category {
#Id
#GeneratedValue
private int idCategory;
private String name;
#ManyToMany(fetch = FetchType.EAGER)
private Set <Product> products;
}
This returns nothing int the view and the loop doesn't rotate even once.
<c:forEach items="${product.categories}" var="items">
<p>${items.name}</p>
</c:forEach>
I join the schema. Could someone write what to do to make it work, please?
enter image description here
This not works.
#Entity
#Table(name="Category")
public class Category {
#Id
#GeneratedValue
private int idCategory;
private String name;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "Product_Category", joinColumns = {
#JoinColumn(name = "Category_idCategory", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "Product_idProduct",
nullable = false, updatable = false) })
private Set <Product> product;
Hibernate infers the sql that it needs to create from the annotation on the objects. Your product entity is telling hibernate to get information about the SQL join from the Category entity. This is from the mappedBy clause in the #ManyToMany annotation.
When it goes to the Category entity, it doesn't find what it needs, and it just gives an empty set.
Most #ManyToMany annotations are done with a join table. Here is a sample join table annotation
#JoinTable(name = "product_to_category", joinColumns = {
#JoinColumn(name = "category_id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "product_id",
nullable = false, updatable = false) })
Depending on your schema, you might need to adjust the above annotation to get it working. It will give you a good start.

Spring Crud on Nested Property

I have a spring crud repository:
#Repository
public interface CrudCVVacancyMatchRepository extends CrudRepository<CVVacancyMatchEntity, Long> {
The CVVacancyMatchEntity object has an Vacancy property. I'm trying to write a query method on properties of the Vacancy property.
The following query method works fine (Vacancy has a string property called name):
Iterable<CVVacancyMatchEntity> findByVacancyName(String name);
But Vacancy also has properties as a set:
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "vacancy_industries", joinColumns = { #JoinColumn(name = "fk_vacancy", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "fk_industry", referencedColumnName = "id") })
private final Set<IndustryEntity> industries = Sets.newHashSet();
This doesn't work:
Iterable<CVVacancyMatchEntity> findByVacancyIndustries(Set<IndustryEntity> industryEntities);
I get ERROR SqlExceptionHelper:146 - Syntax error in SQL statement
select cvvacancym0_.id as id1_19_, cvvacancym0_.comment as comment2_19_, cvvacancym0_.cv_id as cv_id4_19_, cvvacancym0_.rating as rating3_19_, cvvacancym0_.user_id as user_id5_19_, cvvacancym0_.vacancy_id as vacancy_6_19_ from cv_vacancy_match cvvacancym0_ cross join vacancy vacancyent1_ cross join vacancy_industries industries2_, industry industryen3_ where cvvacancym0_.vacancy_id=vacancyent1_.id and vacancyent1_.id=industries2_.fk_vacancy and industries2_.fk_industry=industryen3_.id and .=? [42001-182]
Any idea?

Resources