Spring data JPA , result object has numbers instead of column names - json

i would like some help trying to do the following.I want to get the number of purchases of each user in the database grouped by his name and id.But it's very hard to do compared to simple sql.
I have the following code in my PurchaseRepository that extends CrudRepository
#Query("SELECT p.user.name as Name,p.user.id as Id,Count(p) as Purchases from Transaction p GROUP BY p.user.id")
List<Object> purchaseNumOfEachUser();
First of all im not sure if this is the right query because i wanted to do Count(*) but says its not valid.
Secondly , the object i get returned when converted to Json via a controller is like
0:{
0:"John",
1:2, //id
2:5 //purchases
}
What i would like to get is
0:{
"Name" : "John",
"Id" : 1 ,
"Purchases" : 2
},
1:{
....
}
Any ideas?

1) The query:
SELECT p.user.name as Name, p.user.id as Id, Count(p) as Purchases
from Transaction p GROUP BY p.user.id
should be
SELECT p.user.name as Name, p.user.id as Id, Count(p) as Purchases
from Transaction p GROUP BY p.user.name, p.user.id
You must group by all rows you are selecting.
2) the result
The result of the query is List if you want to have something meaningful you should consider the constructor expression that let's you create your own objects.
For example
package mypackage;
public class PurchaseInfo {
private final String name;
private final Integer id;
private final Long count;
public PurchaseInfo(String name, Integer id, Long count) {
this.name = name;
this.id = id;
this.cound = count;
}
// getters
}
This class can then be use in the query (please notice the fully qualified class name after NEW):
SELECT NEW mypackage.PurchaseInfo(p.user.name, p.user.id, Count(p))
from Transaction p GROUP BY p.user.name, p.user.id
The result will then be List and you will get it nicely serialized to JSON.
Read more about the Constructor Expression here:
https://vladmihalcea.com/the-best-way-to-map-a-projection-query-to-a-dto-with-jpa-and-hibernate/

Related

PetaPoco is mapping 0 for every Id in my object?

I have the following object:
public class VehicleMake
{
[Column(Name = "MakeID")]
public int Id { get; set; }
public string Name { get; set; }
}
To get a list of vehicle makes, I am doing the following:
var vehicleMakes = _db.Fetch<VehicleMake>(#"SELECT DISTINCT(m.MakeID) AS Id, m.Name
FROM vehicles v
INNER JOIN makes m on m.MakeID = v.Make
WHERE [Year] = #year
ORDER BY m.Name", new { year });
When I run the SQL in SSMS, it returns the correct data, but in VS, it is mapping 0 for every Id property.
Ah, I got it, in case anyone else runs into the problem. Since I am doing:
SELECT DISTINCT(m.MakeID) as Id..., there is no reason to have:
[Column(Name = "MakeID")] since I am aliasing the column as Id already.

JPA SQL select and sum from entity manager

The following SQL script works in mysql:
select
LOGGING_ID,
SUM(NORMAL_HOURS +OVERTIME_HOURS +DOUBLE_TIME_HOURS) AS TOTAL_HOURS
FROM
LOGGING_DETAIL
GROUP BY 1
How would I do this with my entity manager?:
#PersistenceContext
private EntityManager database;
List<loggingDetail> loggingDetail = new ArrayList<loggingDetail>();
timeLoggingDetail = database.createQuery("").getResultList();
at the end I want the Logging_id and the total hours for that ID.
Thanks
The entity manager could called a named query that you set on your jpa entity object. I am assuming you have an entity object in this case. I suppose if you don't have that object you could do it in the query like you have it laid out in your question. I like having it in the entity object though so other calls can re-use it.
Entity object -
#Entity
#NamedQuery( name = "loggingDetail.getLoggingId", query = "select
LOGGING_ID,SUM(NORMAL_HOURS +OVERTIME_HOURS +DOUBLE_TIME_HOURS) AS TOTAL_HOURS
FROM LOGGING_DETAIL GROUP BY 1" )
public class LoggingDetail
{ ...}
The entity manager call will not get a fully populated loggingDetail object back since the query is not returning a full object, so you have to loop through an object array -
#PersistenceContext
private EntityManager database;
Query query = database.createNamedQuery( "loggingDetail.getLoggingId" );
List<Object[]> obj = query.getResultList();
for( Object[] objects : obj )
{
String logId = (String) objects[0] ;
String logTime = (String) objects[1] ;
}

Not returning all the required rows using MySQL

so here is my issue:
i have 3 tables:
ROLE : RID ,NAME
CLIENT : CID, NAME
USER : UID, RID, CID, USERNAME, PASSWORD
Below is the SQL statement that I have written:
SELECT USER.UID,USERNAME,PASSWORD,ROLE.NAME, ROLE.RID
FROM USER
INNER JOIN ROLE ON USER.RID=ROLE.RID
WHERE CID=1;
The above statement is returning only 1 row when there should actually be 2 rows.
I don't understand what is not working.
When i do the following, i get my 2 rows:
SELECT *
FROM USER
WHERE CID =1;
Note that i am using spring framework and also implementing a RowMapper. Below is my actual code with the field names as per the dbase.
public List<User> viewUserClient(int client_id) {
String sql =
"SELECT USER.ID,USERNAME,PASSWORD,ACTIVE,ROLE.NAME, ROLE.ID FROM USER INNER JOIN ROLE ON USER.ROLE_ID=ROLE.ID WHERE CLIENT_ID=?";
List<User> users = this.getJdbcTemplate().query(sql, new Object[] { client_id }, new UserClientRowMapper());
return users;
}
private static final class UserClientRowMapper implements RowMapper<User> {
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
Client client = new Client();
Role role = new Role();
user.setID(rs.getInt("ID"));
user.setUSERNAME(rs.getString("USERNAME"));
user.setPASSWORD(rs.getString("PASSWORD"));
user.setACTIVE(rs.getBoolean("ACTIVE"));
role.setNAME(rs.getString("NAME"));
role.setID(rs.getInt("ROLE.ID"));
client.setId(rs.getInt("id"));
client.setName(rs.getString("name"));
user.setRole(role);
user.setClient(client);
return user;
}
}
Thanks in advance for your help.
The INNER JOIN keyword returns rows when there is at least one match in both tables. If there are rows in "USER" that do not have matches in "ROLE", those rows will NOT be listed; of the two users returned by your plain select query, probably one has a null RID column value, or a value that is not in ROLE table.
Use a LEFT JOIN.

LINQ to SQL - Searching column of joined table

I am trying to return a result set that includes rows where any of three strings has a string match. My domain models look like this:
public class Customers
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class BidNames
{
public int BidNameID { get; set; }
public int CustomerID { get; set; }
public string BidName { get; set; }
}
There is a FK between BidName.CustomerID and Customers.CustomerID and it is a one-to-many relationship where there can be multiple BidNames for a single Customer. When searching my customer table I want to bring back all records where there is a string match in FirstName, LastName or any of the associated BidNames. For this example I'll use a BidName search string of "ba".
from c in Customers
where c.FirstName.Contains("ba") || c.LastName.Contains("ba") || c.BidNames.Any(b=>BidNames.BidName.Contains("ba"))
orderby c.LastName, c.FirstName
select new { CustomerID = c.CustomerID, FirstName = c.FirstName, LastName = c.LastName }
It all works until I add the final criteria in the Where clause. I understand that c.BidNames is a collection and I'm looking to see if Any of them have a BidName that contains "ba". Where I'm running into trouble is trying to specify the BidNames.BidName column to search for the string. The code I've written above fails with "BidNames does not contain a definition for 'BidName'"
How do I write the last part of the Where clause so I can search all the BidNames.BidName fields associated with the Customer record? I hope and assume I can use the same syntax to specify the BidName field in the orderby and select clauses as well.
Many thanks,
BK
FINAL ANSWER:
from c in Customers
where
c.FirstName.Contains("ba") ||
c.LastName.Contains("ba") ||
c.BidNames.Any(b=>b.BidName.Contains("ba"))
orderby
c.LastName,
c.FirstName
select new {
CustomerID = c.CustomerID,
FirstName = c.FirstName,
LastName = c.LastName,
BidNames = c.BidNames.OrderBy(b=>b.BidName)
}
Try changing your where clause to
Where c.FirstName.Contains("ba") ||
c.LastName.Contains("ba") ||
c.BidNames.Any(b=>b.BidName.Contains("ba"))
In your Any clause, b is an instance of the BidNames class, so you want to access properties of that rather than the BidNames property of the Customer.

Linq - Add Row to results for display only

I have a linq query that returns a brief order summary - product description and product price that gets bound to a data control. I want to add a row to be bound in this same control that displays tax information. The product description column would simply say "Tax" and the product price column would give a tax amount.
I used to retrieve a DataTable of these results and simply do a NewRow() and then set the datasource of my control as the DataTable. I'm looking for the equivalent technique when using LINQ to SQL. Thanks.
orderSummary.Union(taxRow)
In order to make it easy to add another "row" to the results of the LINQ query, you might want to consider creating a class to hold the results of the query. Then you could convert the results to a List, calculate the tax, and append the tax as an object of the class.
public class OrderSummary
{
public string Description { get; set; }
public decimal Amount { get; set; }
}
var taxRate = ...
var orderSummary = db.Orders.Where( o => o.ID == id )
.Select( o => new OrderSummary
{
Description = o.Product
.Details
.Description,
Amount = o.Qty * o.Product.Price
})
.ToList();
var tax = new OrderSummary
{
Description = "Tax",
Amount = orderSummary.Sum( o => o.Amount * taxRate );
};
orderSummary.Add( tax );
Then you can bind the list to your control using Description as the key and Amount as the value.