JPA Native Query across multiple tables - jpa

I have the following defined as a native query in a repository (dispenseRepository) :
#Query(
value = "SELECT p.*, c.*, s.*, d.* from patient p, consult c ,script s,dispense d "
+ " where p.patient_id=c.patient_id "
+ " and c.consult_id = d.consult_id "
+ " and c.fk_script_id =s.script_id"
+ " and c.consult_id=?1 ",
nativeQuery = true
)
List<Dispense> findInvoiceByConsultId(Long consultId);
The Rest Controller has :
#RequestMapping(value = "/api/invoice/{consultId}",method = {RequestMethod.GET})
public List<Dispense> invoice(#PathVariable(value="consultId")Long consultId){
return dispenseRepository.findInvoiceByConsultId(consultId);
}
When I hit the api I only get dispense details:
[
{
"dispenseId": 1,
"icd10": "J.10",
"tariffCode": "10010",
"dispenseItem": "Lenses",
"price": 400.0
},
{
"dispenseId": 3,
"icd10": "J.10",
"tariffCode": "111000",
"dispenseItem": "Other",
"price": 1500.0
},
{
"dispenseId": 4,
"icd10": "K.100",
"tariffCode": "10010",
"dispenseItem": "Eye Test",
"price": 550.0
}
]
I'd like all the data as per query which will be used for Jasper report
patient-consult 1-M
consult-script 1-1
consult-dispense 1-M

Since in your query you return all fields from all tables: SELECT p.*, c.*, s.*, d.* from patient p, consult c ,script s,dispense d creating projections/DTOs for so many objects and fields is very cumbersome. There are 2 ways to proceed. Either specify exactly the fields you want from each table in your query and create a DTO to hold those fields.
e.g.
Approach 1:
I chose only one field from each table to make it as example. Please not that you have to convert your query from native to jpa one!
#Query("SELECT new com.example.demo.ResultDTO(p.patientName, c.reservationNumber, s.addition, d.dispenseItem) from Patient p, Consult c, Script s, Dispense d ...")
List<ResultDTO> findInvoiceByConsultId(Long consultId);
and ResultDTO class can be:
package com.example.demo;
public class ResultDTO {
private String patientName;
private String reservationNumber;
private String addition;
private String dispenseItem;
public ResultDTO(String patientName, String reservationNumber, String addition, String dispenseItem) {
this.patientName = patientName;
this.reservationNumber = reservationNumber;
this.addition = addition;
this.dispenseItem = dispenseItem;
}
public String getPatientName() {
return patientName;
}
public void setPatientName(String patientName) {
this.patientName = patientName;
}
public String getReservationNumber() {
return reservationNumber;
}
public void setReservationNumber(String reservationNumber) {
this.reservationNumber = reservationNumber;
}
public String getAddition() {
return addition;
}
public void setAddition(String addition) {
this.addition = addition;
}
public String getDispenseItem() {
return dispenseItem;
}
public void setDispenseItem(String dispenseItem) {
this.dispenseItem = dispenseItem;
}
}
UPDATE
Approach 1 won't work with a nativeQuery, you have to convert it to jpa one so unless you convert your query to jpql, the above code wont work.
OR the much easier but bulkier, keep the query as is and place the result on a List of Maps.
Approach 2:
#Query(
value = "SELECT p.*, c.*, s.*, d.* from patient p, consult c ,script s,dispense d "
+ " where p.patient_id=c.patient_id "
+ " and c.consult_id = d.consult_id "
+ " and c.fk_script_id =s.script_id"
+ " and c.consult_id=?1 ",
nativeQuery = true
)
List<Map<String, Object>> findInvoiceByConsultId(Long consultId);

Related

Inheritance doesn't work in Query

I'm new to Spring and i have an issue with the following query:
String rejected_offer_query = "SELECT b.job_instance_id, b.start_time, count (*) " +
"FROM SygaOfferRejected s , BatchJobExecution b, BatchJobInstance bi "+
"where s.heure_debut = b.start_time " +
"and s.heure_fin = b.end_time " +
"and b.job_execution_id = bi.job_instance_id " +
"and bi.job_name = :batchName "+
"and b.status = :batchStatus " +
"group by b.job_instance_id";
It doesn't return data, but it should return one row as a result: (Test made directly with MySql).
I think it's an inheritance problem because when i try to execute the same query with a super class it works :
SELECT b.job_instance_id, b.start_time, count (*) " +
"FROM SygaOffer s , BatchJobExecution b, BatchJobInstance bi "+
"where s.heure_debut = b.start_time " +
"and s.heure_fin = b.end_time " +
"and b.job_execution_id = bi.job_instance_id " +
"and bi.job_name = :batchName "+
"and b.status = :batchStatus " +
"group by b.job_instance_id"
The SygaOfferRejected class extends the SygaOffer, here's the source code;
#Entity
#Inheritance
#Table(name = "bob_syga_off")
public class SygaOffer {
#Id
private long id_offre;
private String acteur;
private String heure_debut;
private String heure_fin;
private String reference_offre;
private int retry;
}
------------------------------------------
#Entity
#Table(name ="bob_syga_offr_rejected")
public class SygaOfferRejected extends SygaOffer{
}
The inheritance strategy is the issue i should specify the TABLE_PER_CLASS type in the parent class :
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
Hope that helps ;)

How can i get entity object with contion JPA

I have 2 Objects Site and Page.
A Site have many Pages.
I get pages with fetch Lazy type.
With a particular reason i want to get pages of a site where the date of pages > val.
#Entity
#Table(name = "site")
Public class Site {
String site_id;
Set<Page> pages;
#OneToMany(mappedBy = "site", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public Set<Page> getPages() {
return pages;
}
}
#Entity
#Table(name = "page")
Public class Page{
String page_id;
Site site;
#ManyToOne(fetch=FetchType.LAZY, cascade = CascadeType.MERGE)
#JoinColumn(name = "site_id")
public Site getSite() {
return site;
}
}
Now in SiteDao i have the mothode to call a site and its pages
#Stateless
public class SiteDao {
#PersistenceContext(unitName = "name")
private EntityManager em;
public Site getSiteAndPages(String site_id) {
Query q = em.createQuery("select s From Site s where s.site_id = :site_id");
q.setParameter("site_id", site_id);
Site s = (Site) q.getSingleResult();
s.getPages();
return s;
}
}
This turns well, but s.getPages() return all the pages and i want to get only some pages using where conditions.
I tried many options like:
Query q = em.createQuery(
"select s, p From Site s"
+ " join s.pages p "
+ " where s.site_id = :site_id "
+ " and p.site = s"
+ " and p.lastupdate > :val"
);
q.setParameter("site_id", site_id);
q.setParameter("val", lastUpdate);
Im bloked after many searches, does any person have an idea about how can i fix this ?
B.R
You need some business methods, you can keep inside Site Class
There are two options
1. Add filter
getLatestPages(Date lastupdate)
{
List pages_= s.getPages();
List latestPages=new ArrayList();
for(Page p: pages_)
{
if(p.getLastUpdatedate().after(lastupdate)) {
latestPages.add(p);
}
}
reutrn latestPages;
}
2.Use query
getLatestPages(EntityManager em, Date lastupdate)
{
Query q = em.createQuery(
"select p From Site s"
+ " join s.pages p "
+ " where s.site_id = :site_id "
+ " and p.site = s"
+ " and p.lastupdate > :val"
);
q.setParameter("site_id", this.site_id);
q.setParameter("val", lastUpdate);
return q.getResultList();
}
Hope this work.

How to restrict to a list of query params for a REST api

I want to restrict to a set of query params for rest Method.
#Path("/users")
public class UserService {
#GET
#Path("/query")
public Response getUsers(
#QueryParam("from") int from,
#QueryParam("to") int to,
#QueryParam("orderBy") List<String> orderBy) {
return Response
.status(200)
.entity("getUsers is called, from : " + from + ", to : " + to
+ ", orderBy" + orderBy.toString()).build();
}
}
“users/query?from=100&to=200&orderBy=age&orderBy=name” [WORKS]
“users/query?x=y” [also works and when my query params are set with default values]
i want throw some exceptions based on that.

How to use graph.getVertices() get specific vertices, Java , Oriendtdb

How to use graph.getVertices() get specific vertices.
My Class name is Station has Extended V(Vertex) .
category' (datatype is LINK)is property of Station
Category's can be '#12:13' or '#12:14' or '#12:15'
I want to use graph.getVertices() JAVA to get specific category.
Something like :
graph.getVertices("Station category = '#12:13'");
graph.getVertices("Excluded Station Category = '#12:13'");
Any suggestion?
I used this simple structure to try your case (category is of type LINK):
CLASSES:
and I retrieved the results you're looking for with this code:
JAVA CODE:
package yourPackage;
import java.io.IOException;
import com.orientechnologies.orient.client.remote.OServerAdmin;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.orient.OrientGraph;
public class YourClass{
private static String remote = "remote:localhost/";
public static void main(String[] args) {
String DBname = "yourDBname";
String currentPath = remote + DBname;
OServerAdmin serverAdmin;
try {
serverAdmin = new OServerAdmin(currentPath).connect("root", "root");
if (serverAdmin.existsDatabase()) {
OrientGraph g = new OrientGraph(currentPath);
String yourRid = "#13:0";
Iterable<Vertex> targets = g.getVerticesOfClass("Station");
System.out.println("Category #rid = " + yourRid);
System.out.println();
for (Vertex target : targets) {
Vertex category = target.getProperty("category");
if (category.getId().toString().equals(yourRid)) {
System.out.println("Matched Station: " + target.getProperty("name") + " Category: "
+ category.getProperty("name") + " (" + category.getId() + ")");
System.out.println();
} else {
System.out.println("Excluded Station: " + target.getProperty("name") + " Category: "
+ category.getProperty("name") + " (" + category.getId() + ")");
}
}
}
else {
System.out.println("Database " + DBname + " not found");
}
serverAdmin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
OUTPUT:
Category #rid = #13:0
Matched Station: First Category: category 1 (#13:0)
Excluded Station: Second Category: category 2 (#13:1)
Excluded Station: Third Category: category 3 (#13:2)
Hope it helps
to get all vertices of Station class, try:
g.V('_class','Station')
or to filter by a category field
g.V('_class','Station').has('category','catvalue 123')
or if you have multiple to match:
g.V('_class', 'Station').has('category', T.in,['12:13','12:14'])
or for specific Id
g.v('12:13')
to find if an edge exists between 2 vertices, you can use:
g.v(stationVtxId).outE('edge_label').sideEffect{x=it}.inV.filter{it == g.v(catVtxId)}.back(2)
I used an index on the property category of the class Station
create class Station extends V
create class Category extends V
create property Station.name STRING
create property Station.category LINK Category
create property Category.name STRING
create index Station.category ON Station (category) NOTUNIQUE
insert into category(name) values ("category A") // 13:0
insert into category(name) values ("category B") // 13:1
insert into Station(name,category) values ("Station 1",#13:0)
insert into Station(name,category) values ("Station 2",#13:1)
JAVA

Entity Framework Firebird MigrationSqlGenerator: Deactivate Transaction for Create and Insert in one Table?

As mentioned here Entity Framework Code First - Firebird migration: No MigrationSqlGenerator? I'm trying to enable Migrations on my Firebird-Database.
for that purpose I'm writing the following implementation of the "MigrationSqlGenerator" (not finished!):
public class FirebirdMigrationSQLGenerator : SqlServerMigrationSqlGenerator
{
protected override DbConnection CreateConnection()
{
return DbProviderFactories.GetFactory("FirebirdSql.Data.FirebirdClient").CreateConnection();
}
protected override void Generate(CreateTableOperation createTableOperation)
{
using (var writer = Writer())
{
WriteCreateTable(createTableOperation, writer);
Statement(writer.InnerWriter.ToString(), true);
}
}
private void WriteCreateTable(CreateTableOperation createTableOperation, IndentedTextWriter writer)
{
writer.WriteLine("CREATE TABLE " + Name(createTableOperation.Name) + " (");
writer.Indent++;
var columnCount = createTableOperation.Columns.Count();
createTableOperation.Columns.Each(
(c, i) =>
{
Generate(c, writer);
if (i < columnCount - 1)
{
writer.WriteLine(",");
}
});
if (createTableOperation.PrimaryKey != null)
{
writer.Write(", PRIMARY KEY ");
writer.Write("(");
writer.Write(createTableOperation.PrimaryKey.Columns.Join(Quote));
writer.WriteLine(")");
}
else
{
writer.WriteLine();
}
writer.Indent--;
writer.Write(")");
}
private void Generate(ColumnModel column, IndentedTextWriter writer)
{
writer.Write(Quote(column.Name));
writer.Write(" ");
writer.Write(BuildColumnType(column));
if ((column.IsNullable != null)
&& !column.IsNullable.Value)
{
writer.Write(" NOT NULL");
}
if (column.DefaultValue != null)
{
writer.Write(" DEFAULT ");
writer.Write(Generate((dynamic)column.DefaultValue));
}
else if (!string.IsNullOrWhiteSpace(column.DefaultValueSql))
{
writer.Write(" DEFAULT ");
writer.Write(column.DefaultValueSql);
}
}
protected override void Generate(InsertHistoryOperation op)
{
using (var writer = Writer())
{
WriteinsertHistory(op, writer);
Statement(writer.InnerWriter.ToString(), true);
}
}
private void WriteinsertHistory(InsertHistoryOperation insertHistoryOperation, IndentedTextWriter writer)
{
StringBuilder model = new StringBuilder();
foreach (byte item in insertHistoryOperation.Model)
model.Append(item.ToString("X2"));
writer.Write("INSERT INTO \"" + insertHistoryOperation.Table.ToUpper() + "\" (migrationId, model, productVersion) ");
writer.Write(" values ( '{0}', '{1}', '{2}') ",
insertHistoryOperation.MigrationId,
"0x" + model.ToString(),
insertHistoryOperation.ProductVersion);
}
protected override string Quote(string identifier)
{
return identifier.Replace("PK_dbo.", "").ToUpper();
}
protected override string Name(string inString)
{
return "\"" + inString.Replace("dbo.", "").ToUpper() + "\"";
}
protected override string BuildColumnType(ColumnModel column)
{
String colType = base.BuildColumnType(column);
if (colType == "INT")
colType = "INTEGER";
return colType;
}
}
My problem is that the __MigrationHistory table is created uppercase. But since the "HistoryContext" is not, the first SELECT-Statement is throwing an Exception:
SELECT
"A"."A1" AS "C1"
FROM ( SELECT
COUNT("B"."A1") AS "A1"
FROM ( SELECT
1 AS "A1"
FROM "__MigrationHistory" AS "B"
) AS "B"
) AS "A"
Normaly I would insert "modelBuilder.Conventions.Remove()"
into the Context, but the HistroyContext is part of the framework and can't be changed...
Any ideas?
My Environment: EntityFramework 5.0.0 .NET 4.5 FirebirdClient 3.0.2.0
In Firebird tablenames are only case sensitive when quoted, so you either need to stop quoting tablenames (both on creation and in queries), or you need to stop upper casing tablenames and use them as is.
For example issueing a CREATE TABLE xyz ( ... ) will create a table XYZ that can be accessed using SELECT * FROM xyz, but also with XyZ,XYZ and "XYZ". It cannot be accessed using "xyz".
Creating a table as CREATE TABLE "xyz" ( ... ) wil create a table xyz, which can only be accessed using SELECT * FROM "xyz", but not with xyz (no quotes) or any other combination of casing and with or without quotes. On the other hand CREATE TABLE "XYZ" ( ... ) can be accessed using SELECT * FROM xyz and "XYZ", and any other case without quoting, but not with SELECT * FROM "xyz".
As far as I can tell from your code, you are creating tables unquoted in WriteCreateTable, therefor the name is stored uppercase, but you are inserting into them quoted. You may also want to look into the contract/expectations of the Quote and Name methods, as it looks to me like you got their implementation reversed (Quote does what Name should do and vice versa).