Extract data using jpa - spring-boot

i have a table that looks this
TableA
id | data
1 | { "name":"a","dob":"12/12/12" }
2 | { "name":"b","dob":"12/12/13" }
I want to extract the data from 'data' column using JPA such
that i get the data in Hashmap form.My current code is something like this
#Query(value="select data from TableA where id=:id",nativeQuery = true)
String findData(#Param("id") String id );
Then in my main code i call this findData method and convert this string into HashMap like this
String data = daoClass.findData(id);
HashMap<String, Object> map = new Gson().fromJson(data, HashMap.class);
However i am not sure if this is the correct way.
Another issue that i have is from another data table which has schema like this
TableB
id | data
1 | { "name":"a","dob":"12/12/12","class":"BV" }
2 | { "name":"b","dob":"12/12/13","class":"SV" }
From this above table i only require 'name' and 'dob' data from table and save them in
a HashMap.My current code is something like this.
#Query(value="select data->>'name',data->>'dob' from TableB where id=:id,nativeQuery = true)
String findData(#Param("id") String id) ;
I am not sure how will i store the result of this above query in a map form ?

Related

Data type of column in JPA fetching through native query

I have a table which looks like this
Table :
id | data
1 | { "name" :"abc","class":"123" }
2 | { "name" :"def","class":"456 }
data type of id = varchar
data type of data = json
i am using native query in jpa like this
#Query(value =
"select data from Table where id=:id"
,nativeQuery = true)
JSONObject findData(#Param("id") String id)
My question is the native query going to return me a JSONObject or a jsonObject in stringified form.if it returns me stringified form should i change return type of native query like this
String findData(#Param("id") String id)

convert join table using rx.net

In my database I have a join table to store many to many relationships between a JobType and DocumentType (simplified description)
JobType Table
Column
Type
Id
int
Description
varchar(100)
DocumentType Table
Column
Type
Id
int
Description
varchar(100)
JobTypeDocumentType with the following columns:
Column
Type
Id
int
JobType
int
DocumentType
int
I want to retrieve the data from the database and convert the result recordset into an IObservable<collection<ViewModels>>.
In the code below, the GetJobDocumentTypes method returns a collection of JobTypeDocumentType POCOs:
IObservable<IReadOnlyCollection<JobTypeDocumentType>> dataService.GetJobDocumentTypes(int jobTypeId)`
The purpose of getJobTypeDocumenTypeViewModels is to transform the returned POCOs into ViewModels:
private IObservable<IEnumerable<JobTypeDocumentTypeViewModel>> getJobTypeDocumenTypeViewModels(JobType jobType)
{
var result = dataService.GetJobDocumentTypes(jobType.Id)
.Select(items => items.Select(jtdt =>
dataService.GetById<DocumentType>(jtdt.DocumentType_Id)
.Select(dt => new JobTypeDocumentTypeViewModel(jtdt, jobType, dt))));
return result;
}
However, I am stuck with result being of type IObservable<IEnumerable<IObservable<JobTypeDocumentTypeViewModel>>>
Any help and/or suggestions would be appreciated.
You have to use SelectMany in this case:
var result = dataService.GetJobDocumentTypes(jobType.Id)
.SelectMany(items => items
.Select(jtdt => dataService.GetById<DocumentType>(jtdt.DocumentType_Id)
.Select(dt => new JobTypeDocumentTypeViewModel(jtdt, jobType, dt)))
);

Using distinct in Spring data over multiple columns

My domain model is like this:
CollectedData {
String name;
String description;
int count;
int xAxis,
int yAxis
}
Using Spring data repository query, I would like to retrieve all the unique rows (unique with name, xAxis, yAxis)
I am trying something like this
#Query("select distinct a.name, a.xAxis, a.yAxis from CollectedData a")
List<CollectedData> findAllDistinctData();
So, when I do
List<CollectedData> records= findAllDistinctData();
for (CollectedData record : records) { //Exception on this line
}
Exception
[Ljava.lang.Object; cannot be cast to CollectedData.
Is there any other way to write query for this ?
#Query return ArrayList of Object(s) instead of specific type of object. so you have to define some thing like
#Query("select distinct a.name, a.xAxis, a.yAxis from CollectedData a")
List<Object> findAllDistinctData();
then cast according to your requirement,
List<Object> cdataList=findAllDistinctData();
for (Object cdata:cdataList) {
Object[] obj= (Object[]) cdata;
String name = (String)obj[0];
String description = (String)obj[1];;
...
}
Instead of returning an object you can use JPA's constructor expression feature to return a more specific object holding only the columns you're interested in. See also following answer:
JPQL Constructor Expression - org.hibernate.hql.ast.QuerySyntaxException:Table is not mapped
According to your example you could create a new Object with only the columns you are interested in:
SELECT DISTINCT new com.mypackage.MyInterestingCollectedData(a.name, a.xAxis, a.yAxis) from CollectedData a
If you want to select complete object based on distinct values of multiple columns,
In that case the native query would be the option.
e.g.
#Query(
value = "select distinct on (column1, column2, column3) * From my_table where someId=: order by column1 asc,column2 desc,column3 desc,column4 desc",
nativeQuery = true
)
fun finalAllDistinctBy(containerId: String): List<MyTable>

Linq to Entities, Take(3) from Joined table

I am trying to populate a ViewModel in an MVC app with data from a parent table joined with a child table. The only data I want from the child table is a comma diliminated string from the Nomenclature field of the top three records and put them into a string field in the ViewModel. Here is what I have tried without success:
public IEnumerable<ReqHeaderVM> GetOpenReqs(string siteCode)
{
var openReqs = from h in context.ReqHeaders
join l in context.ReqLineItems on h.ID equals l.ReqID into reqLineItems
select new ReqHeaderVM
{
ReqID = h.ID,
ShopCode = h.ShopCode
Nomenclatures = reqLineItems.Select(x => x.Nomenclature).Take(3) // This doesn't work
};
return (openReqs.ToList());
}
Here is the ViewMdel:
public class ReqHeaderVM
{
[Editable(false)]
public string ReqID { get; set; }
public string ShopCode { get; set; }
public string Nomenclatures {get; set;}
}
Assuming that you have proper relationship (foreign key) between ReqHeaders and ReqLineItems, this should give you what you are looking for...
public IEnumerable<ReqHeaderVM> GetOpenReqs(string siteCode)
{
var openReqs = from h in context.ReqHeaders
select new
{
ReqID = h.ID,
ShopCode = h.ShopCode
Nomenclatures = h.ReqLineItems
.OrderBy(x => x.SomeColumn)
.Select(x => x.Nomenclature)
.Take(3)
};
var openReqsTran = from oreq in openReqs.AsEnumerable()
select new ReqHeaderVM
{
oreq.ReqID,
oreq.ShopCode,
Nomenclatures = string.Join(", ", oreq.Nomenclatures)
};
return (openReqsTran);
}
Note that Nomenclatures is a list of type of Nomenclature.
Yes, the join creates a single Cartesian result set. (think tabular data) what you are attempting to do. To get the results you want you have a few choices.
use lazy loading and iterate over each header querying the line items individually.
pro - simple queries
con - select n+1
query all headers and all line items, but build view model with only the top 3
pro - single query
con - large Cartesian result set query too much data
query all headers and all associated lines individuals
pro - 2 smaller, simpler queries
con - query too many line details.
query all headers and top 3 lines per header in 2 queries
pro - get only the information you require
con - complex query for top 3 lines per header.

How to declare the result of query in LINQ to Entities

I just started using MS entity framework and have the following problem with LINQ. I will simplify my problem to make it clearer; let's say that I have three tables in SQL Server database:
CustomerData (PK is CustomerId, the table also has some twenty columns to hold customer data).
CustomerData1 (holds some data for the customer in one to one relationship).
CustomerData2 (also holds some data for the customer in one to one relationship).
I know the data with one to one relationship should better be in the same table, but this is some corporate db and it is not possible to alter the original table (so all our data should be in the separate tables).
Now I want to display a list of customer with their data from CustomerData table and add some data columns from CustomerData1 via join.
On the other hand, I want to display a list of customers and add some data from the other table CustomerData2 via join.
So the data is basically the same both times except that in the first case the result includes some columns from CustomerData1 and in the second case some data from CustomerData2 table.
So I created the class Customer with properties for all relevant columns in CustomerData table and added properties for columns that should be included from CustomerData1 and properties that should be included from CustomerData2.
All columns should be included each time, except that when first call will be made the properties that map to CustomerData2 table will be empty and during the second call the properties that map to CustomerData1 table will be empty.
For this I wanted to create one function so I tried to create it like this:
Input parameter in function is whether data from CustomerData1 or CustomerData2 is included.
if (firstList)
{
var query1 = from obj in CustomerData
join rel in CustomerData1
on obj.CustomerId equals rel.CustomerId
select new { obj, rel };
}
if (secondList)
{
var query2 = from obj in CustomerData
join rel in CustomerData2
on obj.CustomerId equals rel.CustomerId
select new { obj, rel };
}
So this code gives me the anonymous type based on the input parameter. Now I want to create Customer objects and order it (order is always the same, it does not depend on input parameter). So I want to create a list of ordered customers and include additional data based on the input parameter.
var query3 = <previous_query_variable>.Select(f => new Customer {
Id = f.obj.CustomerId,
Name = f.obj.CustomerName,
... other columns from Customer table (a lot of them)
//and then add some additional columns based on the input parameter
Data1 = f.rel.someDataFromCustomer1, //only when firstList == true, otherwise empty
Data2 = f.rel.someDataFromCustomer2 //only when secondList == true, otherwise empty
}).OrderBy(f => f.Name); //order by customer name
Of course this does not compile, since both vars are inside if statements. I know I could copy this last statement (var query3 = ...) inside both if statements and include only relevant assignments (Data1 or Data2), but I don't want to assign properties that map to CustomerData table twice (once in both if statements) nor I want to order twice.
How can I solve this problem? I am using .NET 4.
You cannot declare a variable for an anonymous type up-front, i.e. before your two if statements. (Something like var query = null is not supported.) You will have to create a helper type and project into it, like so:
public class ProjectedCustomerData
{
public CustomerData CustomerData { get; set; }
public CustomerData1 CustomerData1 { get; set; }
public CustomerData2 CustomerData2 { get; set; }
}
And then the projection:
IQueryable<ProjectedCustomerData> resultQuery = null;
if (firstList)
{
resultQuery = from obj in CustomerData
join rel in CustomerData1
on obj.CustomerId equals rel.CustomerId
select new ProjectedCustomerData
{
CustomerData = obj,
CustomerData1 = rel
};
}
if (secondList)
{
resultQuery = from obj in CustomerData
join rel in CustomerData2
on obj.CustomerId equals rel.CustomerId
select new ProjectedCustomerData
{
CustomerData = obj,
CustomerData2 = rel
};
}
var query3 = resultQuery.Select(f => new Customer {
Id = f.CustomerData.CustomerId,
Name = f.CustomerData.CustomerName,
// ...
Data1 = f.CustomerData1.someDataFromCustomer1,
Data2 = f.CustomerData2.someDataFromCustomer2
}).OrderBy(f => f.Name);
I am not sure if Customer is an entity in your model or only a class you are using for your projection. If it's an entity you have to change the last code because you cannot project into an entity (basically you would need another helper type for your projection).

Resources