How to use FIELD() function of mysql in JPA - mysql

My sql query is something like
Select * from tableA order by FIELD('ID', 3, 5, 2)
How do I implement this in JPA using criteria builder?
EDIT
List<Integer> ordList = new ArrayList<Integer>();
ordList.add(3);
ordList.add(5);
ordList.add(2);
public List<Order> getOrderBys(CriteriaBuilder cb, Root<?> root) { 
List<Order> orders = new ArrayList<Order>();         
orders.add(cb.function("FIELD", Integer.class, root.get("id"), ordList));
     return orders; 
}
Above is my function which gives list of oders, I want to add only one order same as above sql query. How can I add/call that function in orders.add() method? The above method gives error.

We can use with the native query flag.
For example.,
#Query(value="select * from table_name where id IN :id ORDER BY FIELD(id,:id)",nativeQuery = true)
List<Entity Name> getByIds(#Param("id") List<Integer> id);

For that simple case I would not use the FIELD function but would sort the result by the sorted list, as described here.
E.g.:
List<Integer> ordList = new ArrayList<Integer>();
ordList.add(3);
ordList.add(5);
ordList.add(2);
List<Entity> resultList = query.getResultStream()
.sort(Comparator.comparing(entity -> ordList.indexOf(entity.getId())))
.collect(Collectors.toList();

Related

hibernate optional relationship not showing data

I am using hibernate with MySQL Db. I have a table of business with some fields and relations. in relations, one relation is optional.
#ManyToOne(fetch = FetchType.LAZY)
#NotFound(action=NotFoundAction.IGNORE)
#JoinColumn(name = "modified_by", nullable = true)
public Users getModifiedBy() {
return this.modifiedBy;
}
public void setModifiedBy(Users modifiedBy) {
this.modifiedBy = modifiedBy;
}
now when I fetch data using the following hql it work fine
String hql = "from Business";
Query query = session.createQuery(hql);
list = query.list();
if i changed hql to the following then it shows 0 result.
String hql = "select new com.ba.Business(business.businessId,business.slUsersByCreatedBy.userId,business.modifiedBy.userId,business.bizType.bizTypeId) from com.ba.Business business order by business.businessName";
How to manage this as modifiedBy is null. There were different solution available which i tried like setting optional to true and setting #NotFound but nothing worked.
SQL Created by hql is following.
select business0_.business_id as col_0_0_, business0_.createdBy as col_1_0_, business0_.modified_by as col_5_0_, business0_.biz_type_id as col_9_0_ from _business business0_, _users users1_, _users users4_, _biz_type biztype7_ where business0_.createdBy= users1_.web_user_id and business0_.modified_by= users4_.web_user_id and business0_.biz_type_id= biztype7_.biz_type_id order by business0_.business_name
it is using "and" for joins. If i explicitly add joins by adding following with hql then the result remain same.
left join business.modifiedBy modifiedBy
Is there any solution available?
When you use business.modifiedBy in the query, it implicitly converts to inner join, and that's why you don't get any results. Change it to this and it should work
String hql = "select new com.ba.Business(business.businessId, business.slUsersByCreatedBy.userId, mb.userId, business.bizType.bizTypeId) from com.ba.Business business left join business.modifiedBy mb order by business.businessName";

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] ;
}

Why is LINQ to SQL Omitting Columns in Select

I'm using LINQ to SQL to select records. I need to union two queries together but the select statements are being changed so that the expressions no longer match preventing the union.
This LINQ query omits my forced columns 'resultType' and 'imageFile' from the final result.
var taglist = from t in dc.ProductTags
where t.Tag.StartsWith(prefixText)
select new AutoSearch {
resultType = "Tag",
name = t.Tag,
imageFile = string.Empty,
urlElement = t.Tag };
This is the query that is presented.
{SELECT [t0].[Tag] AS [name] FROM [dbo].[ProductTag] AS [t0] WHERE [t0].[Tag] LIKE #p0}
This is the second query to be unioned with the initial one.
var brandlist = from b in dc.Businesses
join t in dc.Tags on b.BusinessId equals t.BusinessId
where b.Name.StartsWith(prefixText)
where b.IsActive == true
where t.IsActive == true
select new AutoSearch
{
resultType = "Business",
name = b.Name,
imageFile = t.AdImage,
urlElement = b.BusinessId.ToString() };
This is the sql for the second query.
SELECT [t0].[Name] AS [name], [t1].[AdImage] AS [imageFile], CONVERT(NVarChar(MAX) [t0].[BusinessId]) AS [urlElement] FROM [dbo].[Business] AS [t0] INNER JOIN [dbo].[Tag] AS [t1] ON ([t0].[BusinessId]) = [t1].[BusinessId] WHERE ([t0].[Name] LIKE #p0)
The union... that throws the error.
var unionedResults = taglist.Union(brandlist);
The error thrown.
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
This is the AutoSearch class.
public class AutoSearch
{
public string name { get; set; }
public string imageFile { get; set; }
public string resultType { get; set; }
public string urlElement { get; set; }
}
Suggestions as to what is going???
UPDATE***
Found a work around...
Found the issue.
This is a known bug in LINQ, several discussions found here on SO that pointed me in the right direction. Turns out most of the work arounds listed on the site are no longer valid because version 4.0 of broke them too. I found another that worked..
LINQ omits duplicate values for optimization purposes. I was able to change the values of the throw away fields by converting them to strings or lower case or concatenating them.
Terribly inefficient, but it works. Whole day lost for me on this one, perhaps it will save others time.
var taglist = from t in dc.ProductTags
where t.Tag.StartsWith(prefixText)
let resultType = "Tag"
select new AutoSearch() {
resultType = resultType,
name = t.Tag,
imageFile = t.Tag.ToString(),
urlElement = t.Tag.ToLower()
};
var brandlist = from b in dc.Businesses
join t in dc.Tags on b.BusinessId equals t.BusinessId
where b.Name.StartsWith(prefixText)
where b.IsActive == true
where t.IsActive == true
where t.AdImage != null
where t.AdImage != String.Empty
let resultType = "Business"
select new AutoSearch
{
resultType = resultType,
name = b.Name,
imageFile = t.AdImage,
urlElement = b.BusinessId.ToString()
};
The only property you reference when you do the select part of your query is Tag, Linq to Sql knows this and optimizes the query to only select columns you're referencing.
In other words, this section of your query only refers to the "Tag" property, which is tied to the Tag column on your database.
new AutoSearch {
resultType = "Tag",
name = t.Tag,
imageFile = string.Empty,
urlElement = t.Tag };
What Linq does in this case is pass an expression to the underlying provider (very similar to a binary tree data structure). The provider then parses this tree and creates a SQL query from it at run time. The optimization is done by the provider at runtime which results in the SQL query you're seeing.
Update
For the second problem with the union you basically are trying to union two different SQL statements which is causing the union error. So lets take a look.
The resulting statement that would be causing the error would look something like this
SELECT [t0].[Tag] AS [name] FROM [dbo].[ProductTag] AS [t0] WHERE [t0].[Tag] LIKE #p0
UNION
SELECT [t0].[Name] AS [name], [t1].[AdImage] AS [imageFile], CONVERT(NVarChar(MAX) [t0].[BusinessId]) AS [urlElement] FROM [dbo].[Business] AS [t0] INNER JOIN [dbo].[Tag] AS [t1] ON ([t0].[BusinessId]) = [t1].[BusinessId] WHERE ([t0].[Name] LIKE #p0)
Obviously this is problametic since there is not the same number of columns between the two and that doesn't fly with SQL. While I do not have a pure linq solution there is a workaround.
First You'll need to create a SQL function that just returns a string sent to it.
CREATE FUNCTION ReturnString( #string varchar(max) )
RETURNS varchar(max)
AS
BEGIN
RETURN #string
END
GO
Next drag and drop this new SQL function into your dbml file, and finally in your query simply call the method where appropriate.
var taglist = from t in dc.ProductTags
where t.Tag.StartsWith(prefixText)
select new AutoSearch
{
resultType = dc.ReturnString("Tag"),
name = t.Tag,
imageFile = dc.ReturnString(string.Empty),
urlElement = dc.ReturnString(t.Tag)
};
var brandlist = from b in dc.Businesses
join t in dc.Tags on b.BusinessId equals t.BusinessId
where b.Name.StartsWith(prefixText)
where b.IsActive == true
where t.IsActive == true
select new AutoSearch
{
resultType = dc.ReturnString("Business"),
name = b.Name,
imageFile = t.AdImage,
urlElement = b.BusinessId.ToString()
};
Now you should be able to perform the union.

LInq-to-sql dynamic sorting problem

I have a linq-to-sql query over entity that has child entityset that I need to sort on some child fields, i.e. use this query:
var query = from p in context.Patients
let order = p.Lab_Orders.First()
orderby order.Order_Date
select p;
This query runs fine, but how would I modify it to use DLINQ OrderBy method what would I pass as a sorting parameter in run-time?
If by DLINQ you mean Dynamic Query, then you can't use the query expressions like that, you have to use extension methods with lambdas. You can start with a query expression but you have to eventually switch it over to lambda:
IEnumerable<Patient> GetPatients(string orderSortField)
{
var query =
from p in context.Patients
select new
{
Patient = p,
FirstOrder = p.Lab_Orders.First()
};
return p.OrderBy(orderSortField).Select(p => p.Patient);
}
Call it with:
var patientsByOrderDate = GetPatients("FirstOrder.Order_Date");
Use the AsQueryable() after the initial statement -
var query = from p in context.Patients
let order = p.Lab_Orders.First()
select p;
query = query.AsQueryable().OrderBy(x => x.Lab_Orders.First().OrderDate);
Try to add the "OrderBy" to the expression tree:
var query = from p in context.Patients
let order = p.Lab_Orders.First()
select p;
var x = Expression.Parameter(query.ElementType, "x");
string sortName = "order.Order_Date";
var selector = Expression.Lambda(Expression.PropertyOrField(x, sortName), x);
query = query.Provider.CreateQuery(
Expression.Call(typeof(Queryable), "OrderBy",
new Type[] { query.ElementType, selector.Body.Type },
query.Expression, selector)
) as IQueryable<Patients>;
Needs the namespace "System.Linq.Expressions".

How can I get an OR in my Where clause?

I'm building an ad-hoc query to send to SQL doing the following:
var data = from d in db.xxxx select d;
foreach (pattern in user_stuff)
data = data.Where(d=>SqlMethods.Like(d.item,pattern)==true);
The problem is that the WHERE clauses get AND'ed together. I need OR's.
Any idea how to get an OR?
How about I answer my own question:
PredicateBuilder
You need to construct an Expression to represent the composite OR predicate, then pass that to Where:
var data = from d in db.xxxx select d;
Expression<Func<Data, bool>> predicate = null;
foreach (var pattern in user_stuff)
{
Expression<Func<Data, bool>> newPredicate = d => SqlMethods.Like(d..item, pattern));
if (predicate == null) predicate = newPredicate;
else predicate = Expression.OrElse(predicate, newPredicate);
}
return data.Where(predicate);
EDIT: This is probably what PredicateBuilder does, only a lot messier :)