I have two tables
Table A
Table B
Table A contains
Column X
Column Y
Column Z
Column W
Tables B Contains
Column P
Column Q
Column R
Column W
Column W is common in both the tables.
and their entities
First Entity
#Entity
#Table(name = "A")
#Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class TableA extends AbstractBaseEntity {
#Id
#NotNull
#Column(name = "X")
private Long sampleId1;
#Id
#NotNull
#Column(name = "Y")
private Long sampleId2;
#Id
#NotNull
#Column(name = "Z")
private Date sampleDate3;
#ManyToOne(targetEntity = TableB.class)
#JoinColumn(name = "W")
private TableB tableB;
...
getter
setter
....
}
Second Entity
#Entity
#Table(name = "TableB")
#Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class TableB extends AbstractBaseEntity {
#Id
#NotNull
#Column(name = "W")
private Long sampleId4;
#Id
#NotNull
#Column(name = "P")
private Long sampleId1;
#Id
#NotNull
#Column(name = "Q")
private Long sampleId2;
#Id
#NotNull
#Column(name = "R")
private Long sampleId3;
...
getter
setter
....
}
I have an Interface where all the queries are written
Public interface sqlquery{
String query1 = "from TableA ORDER BY" +
sampleDate3 asc;";
String query2= "from TableB";
}
Right now i am fetching all data separately in these query,
I need some help in writing a new single query where data should be shown on the basis of same ID i.e SampleId4(column W)
using JOIN clause and where.
and store the data in result list.
Your mapping doesn't make much sense. If all the columns in table B are part of the ID, that probably means that you might have several rows in it which have the same value in column W. So, if a row in table A has this shared value, it actually references all these rows of table B. So you don't have a ManyToOne association between TableA and TableB.
Regarding your query, since the mapping is wrong in the first place, I don't see how I could write it. End even if it was OK, you should tell us what the query should return, because it's far from being clear.
Related
in my spring data application i have two TABLE VIEW mapped:
the first view
#Entity
#Immutable
#Table(name="VD_CONT")
#NamedQuery(name="VdContr.findAll", query="SELECT d FROM VdContr d")
public class VdContr {
#Id
#Column(name="CONTR_ID")
private Long id;
#Column(name="CF")
private String cf;
#OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="vdcontr")
private List<VdArr> vdArr;
}
and the second view
#Entity
#Immutable
#Table(name="VD_ARR")
#NamedQuery(name="VdArr.findAll", query="SELECT v FROM VdArr v")
public class VdArr {
#Id
#Column(name="ARR_ID")
private Long id;
#Column(name="FK_CONTR_ID")
private Long fkContrId;
#ManyToOne(fetch=FetchType.LAZY)
public VdContr vdcontr;
}
If i put a relationship "OneToMany" and "ManyToOne" (1, first view : many, second view), i receive errors.
My question is: is it possibile create a relationship between two table view?
you need to add a #JoinColumn to VdContr.
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "vdcontr_id", nullable = false)
In general, views are mapped in the same way as tables.
By looking at your classes, the problem is that Hibernate cannot find the correct join column. You need to specify it.
Also, in your VdArr you should delete the fkContrId, because hibernate will need to use this column to map the VdContr relationship.
By looking at your code, the join column is FK_CONTR_ID, so you need to specify it by using #JoinColumn.
#Entity
#Immutable
#Table(name = "VD_ARR")
#NamedQuery(name = "VdArr.findAll", query = "SELECT v FROM VdArr v")
public class VdArr {
#Id
#Column(name = "ARR_ID")
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "FK_CONTR_ID")
public VdContr vdcontr;
}
I see a lot of posts where Eager fetch performs left join of child table parent table in hibernate. But when I use springboot , hibernate fires seperate sql queries - means one select query for parent table and one select query for child table. Why is there a difference? Has there been any upgrades in springboot or is it something I am doing wrong ?
Below are the entities I am using:
Order Entity:
#Entity
#Table(name="Ordertable", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Order {
#Id
#Column(name = "ORDER_ID")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int orderId;
#Column(name = "DAT_SRC_ID")
private String dataSourceId;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
private Customer customer;
}
Customer Entity:
#Entity
#Table(name="Customer", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Customer {
#Id
#Column(name = "CUSTOMER_ID")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long customerId;
#Column(name = "CUSTOMER_NAME")
private String customer_name;
#Column(name = "CUSTOMER_address_id")
private int customer_address_id;
#Column(name = "DAT_SRC_ID")
private String dataSourceId;
#OneToMany(fetch=FetchType.EAGER)
#JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
private List<Order> order;
}
Controller:
#RequestMapping(value="/getByCustid/{id}", method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)
public Customer getByCustid (#PathVariable Long id) {
Customer s1 = customerRepository.findByCustomerId(id);
return s1;
}
Repository:
public interface CustomerRepository extends JpaRepository<Customer,Long> {
public Customer findByCustomerId(Long customerId);
}
Below are the queries that are getting executed:
select
customer0_.CUSTOMER_ID as CUSTOMER1_0_,
customer0_.CUSTOMER_address_id as CUSTOMER2_0_,
customer0_.CUSTOMER_NAME as CUSTOMER3_0_,
customer0_.DAT_SRC_ID as DAT_SRC_4_0_
from
Customer customer0_
where
customer0_.CUSTOMER_ID=?
select
order0_.ORDER_CUSTOMER_ID as ORDER_CU3_5_0_,
order0_.ORDER_ID as ORDER_ID1_5_0_,
order0_.ORDER_ID as ORDER_ID1_5_1_,
order0_.ORDER_CUSTOMER_ID as ORDER_CU3_5_1_,
order0_.DAT_SRC_ID as DAT_SRC_2_5_1_
from
Ordertable order0_
where
order0_.ORDER_CUSTOMER_ID=?
EDIT : is this related to #Fetch(FetchMode.JOIN) -- Link:JPA eager fetch does not join
Hibernate: Multiple select queries made by Hibernate for Fetch mode Eager
To check whether FetchMode.JOIN works, I have added FetchMode.JOIN in entities as shown below but still no success with Join Query:
Customer Entity:
#Entity
#Table(name="Customer", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Customer {
#OneToMany(fetch=FetchType.EAGER)
#JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
#Fetch(FetchMode.JOIN)
private List<Order> order;
}
Order Entity:
#Entity
#Table(name="Ordertable", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Order {
#JsonIgnore
#ManyToOne()
#JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
#Fetch(FetchMode.JOIN)
private Customer customer;
}
The findByCustomerId will actually generate a query based on that method instead of using em.find. It will create something along the lines of SELECT c FROM Customer c WHERE c.customerId=:customerId. afterwards it will notice the fetch strategy and obtain the needed references. This is also explained here. The query will do exactlly what you instruct it to do.
If you want to eagerly load the reference you would need to write the query yourself along the lines of SELECT c FROM Customer c JOIN FETCH c.orders o WHERE c.customerId=:customerId, this will automatically retrieve the orders.
However the customerId is actually the primary key or identitifier for your entity and thus you should actually be using the findById or findOne method (depending on your Spring Data JPA version). This will use the EntityManager.find which should take the mapping information into account and create the appropriate query.
I'm using spring boot version 2.0.3.RELEASE and spring data jpa version 2.0.8.RELEASE. I have two tables TableA, TableB and they are one to one mapped.
TableA
#Entity
#Table(name = "table_a")
public class TableA {
#Id
#Column(name = "id")
private Long id;
#OneToOne(mappedBy = "table_b", cascade = CascadeType.ALL)
private TableB tableB;
}
TableB
#Entity
#Table(name = "table_b")
public class TableB {
#Id
#Column(name = "id")
private Long id;
#OneToOne
#JoinColumn(name = "id")
private TableA tableA;
}
I need to get TableA values when the Mapped TableB is not existed. I wrote below query in TableA Jpa Repository.
#Query(value = "select a from TableA a where a.tableB is null and a.id=?1")
TableA findTableAValues(Long id);
But it doesn't give the expected result. If I replaced the is null with the is empty key word, query gives the expected result. Please anyone can explain why this kind of thing is happened?
The IS EMPTY operator is the logical equivalent of IS NULL, but for collections.
You can visit this link for more details and examples http://www.java2s.com/Tutorials/Java/JPA/4070__JPA_Query_Is_Empty.htm
I'm using QueryDSL JPA, and want to do a join between two tables. I found many similar questions here already, but my case is different from all of them by one little detail. Here is a simplified version of my classes:
#Entity(name = "TABLE_A")
public class TableA {
#Id
#Column(name = "ID_A", nullable = false)
private Long idA;
}
#Entity(name = "TABLE_B")
public class TableB {
#Id
#Column(name = "ID_B", nullable = false)
private Long idB;
}
#Entity(name = "TABLE_C")
public class TableC {
#Id
#Column(name = "ID_C", nullable = false)
private Long idC;
#JoinColumn(name = "ID_A", referencedColumnName = "ID_A")
#ManyToOne
private TableA tableA;
#JoinColumn(name = "ID_B", referencedColumnName = "ID_B")
#ManyToOne
private TableB tableB;
}
Now what I want to do is join Tables A, C and B, to find the Bs which are linked to A. I know this seems like a useless step between, why not add a relation from A to B directly. In my case this is needed, these are just example classes to illustrate.
I tried this:
QTbTableA tableA = QTbTableA.tableA;
QTbTableB tableC = QTbTableC.tableC;
JPAQuery query = new JPAQuery(entityManager).from(tableA);
query.leftJoin(tableA, tableC.tableA);
The join throws an Exception because tableC.tableA is not a root path, only a property. But how do I join these tables correctly then?
Thanks in advance!
If you want to keep your current impl, you could start from TableC and then join the other tables:
query.from(tableC)
.innerJoin(tableC.tableA, tableA)
.innerJoin(tableC.tableB, tableB)
.where(tableA.idA.eq(myId)
.list(tableB);
I have two entities:
#Entity
class X {
#Id
int id;
}
#Entity
class Y {
#Id
int id;
#ManyToOne
#JoinColumn(name = "x_id")
X x;
}
I would like to count distinct values of x_id in y table. I've tried:
select count(distinct Y.x) from Y;
It works but in sql i get join to x table which is uneccesery:
select count(distinct x.id) from y, x where y.x_id = x.id;
This join is unnecessary and quite costly for me. Is there any way to avoid it without native query?
You may try with select count(distinct Y.x.id) from Y (T.x.id instead of Y.x). I am not sure, but intelligent JPA implementation should find out that only id is necessary and would not add the join.
Alternative is to add a int field to Y with a read-only mapping to x_id column:
#Entity
class Y {
#Id
int id;
#ManyToOne
#JoinColumn(name = "x_id")
X x;
#Column(name = "x_id", insertable = false, updatable = false, nullable = false)
int xId;
}
And the your query would be simply select count(distinct Y.xId) from Y
For count inside the JPA repository, you can even use:
Suppose there are two entities: EntityA and EntityB. If EntityA has any relation with EntityB then you can use count in your
#Entity
#Table(name = "entity_a")
public class EntityA {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ea_id")
private Long eaId;
#ManyToOne
#JoinColumn(name = "eb_id")
private EntityB entityB;
...
}
And another EntityB
#Entity
#Table(name = "entity_b")
public class EntityB {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "eb_id")
private Long ebId;
...
}
For this, you can use the following method in your JPARepository of EntityA for getting the count. Remember _ is the replacement of . for method signature in the repository.
int countByEntityB_EbId(long ebId);