PlayFramework get field from model select - java

Since the play documentation on models is terrible I'll ask here. I have the basic code;
public static void Controller() {
List<Item> item = Item.find("SELECT itemname,id FROM Item WHERE itembool = true ORDER BY itemcreated ASC LIMIT 0,1").fetch();
if ( item == null ) {
notFound();
}
}
What I'm trying to do is get the value for 'itemname' returned for the first value returned from an SQL query (The real query is much more complicated and other things so it can't be replaced with methods). I can get the entire first object with item.get(0) but I can't figure out how to get the value of 'itemname' as a string and it doesn't seem to be documented anywhere.
Edit
Probably should have mentioned in the original question, I need to retrieve by field name, not index. I.E. I can't do items.get(0)[0]; I need to do items.get(0)['itemname'];

The documentation explains this if you read it, in here. Hibernate doesn't use SQL, but JPQL, which has a different syntax as it works with objects, not individual fields.
What you want to do can be achieved in two ways (both in the documentation):
List<Item> item = Item.find("SELECT i FROM Item i WHERE i.itembool = true ORDER BY i.itemcreated ASC").fetch(1);
List<Item> item = Item.find("itembool = true ORDER BY itemcreated ASC").fetch(1);
EDIT:
On the retrieval part, you will get a list of Item, so you can just access the field directly on the object:
item.get(0).getItemName();

Since Play uses Hibernate under the hood, you need to take a look at Hibernate's documentation.
In particular, SELECT itemname,id ... yields Object[] rather than Item, so that you can get itemname as follows:
List<Object[]> items = ...;
String itemname = items.get(0)[0];

well if you have to do a select itemname,id ..., you would not be able to do a items.get(0)["itemname"] because as axtavt and Pere have mentioned, you would get a Object[] back. You can instead create another (perhaps immutable) entity class that can be used in this query. Please refer to hibernate documentation for details. You can then model the entity based on your query requirements and use it to fetch information, thus letting hibernate handle all the magic number game for you. That ways, you would have a bean with filled up values that you can use to map back to your model class if you like.
HTH!

Related

Indexing a simple Java Record

I have a Java Object, Record . It represents a single record as a result of SQL execution. Can CQEngine index collection of Record ?
My class is of the form
public class Record {
private List<String> columnNames;
private List<Object> values;
... Other getters
}
I have looked through some examples, but I have no luck there.
I want to index only specific column(s) with its name and corresponding value. Can this be achived using cqengine or is there any other alternatives to achieve the same.
Thanks.
That seems to be a strange way to model data, but you can use CQEngine with that model if you wish.
(First off, CQEngine will have no use for your column names so you can remove that field.)
To do this, you will need to define a CQEngine virtual attribute for each of the indexes in your list of values.
Each attribute will need to be declared with the data type which will be stored in that column/index, and will need to be able to cast the object at that index in your list of values, to the appropriate data type (String, Double, Integer etc.).
So let's say your Record has a column called 'price', which is of type Double, and is stored at index 5 in the list of values. You could define an attribute which reads it as follows:
public static final Attribute<Record, Double> PRICE =
attribute("PRICE", record -> ((Double) record.values.get(5));
If this sounds complicated, it's because that way of modelling data makes things a bit complicated :) It's usually easier to work with a data model which leverages the Java type system (which your model does not). As such, you will need to keep track of the data types etc. of each field programmatically yourself.
CQEngine itself will work fine with that model though, because at the end of the day CQEngine attributes don't need to read fields, the attributes are just functions which are programmed to fetch values.
There's a bunch of stuff not covered above. For example can your values be null? (if so, you should use the nullable variety of attributes as discussed in the CQEngine docs. Or, might each of your Record objects have different sets of columns? (if so, you can create attributes on-the-fly when you encounter a new column, but you should probably cache the attributes you have created somewhere).
Hope that helps,
Niall (CQEngine author)

How to retrieve only part (few) of pojo fields in Hibernate?

I have a situation where I need to return only few fields of a POJO.
Here is a SOF Question: retrieve-single-field-rather-than-whole-pojo-in-hibernate question regarding the same, but few things still seems to be obscure.
1) The answer suggests to use -
String employeeName = session.createQuery("select empMaster.name from EmployeeMaster empMaster where empMaster.id = :id").setInteger("id",10).uniqueResult();
So, here is my concern - Every pojo field is normally private, so "empMaster.name" will simply not work. And am not sure if empMaster.getName() is the solution for this. Will calling the getter methods work?
2) If i am querying multiple fields, (which is my case) (assuming getter methods work) the query will be some thing like -
List<String> employeeDetails = session.createQuery("select empMaster.getName(), empMaster.getDesignation() from EmployeeMaster empMaster where empMaster.id = :id").setInteger("id",10).uniqueResult();
Note the return type has changed from String to List<String>.
2(a) Hope this is right?
2(b) what if i am interested in age/salary of employee which will be of int type. I think the return type will be List<String> or List<Object>. Well any how in the application i can recast the String or Object to the proper type int or float etc. So this should not be a problem.
3) Now what if I am querying multiple employee details (no where clause), so the query will be something like - (not sure if the part of query after from is correct)
List<List<<String>> employeesDetails = session.createQuery("select empMaster.getName(), empMaster.getDesignation() from EmployeeMaster;
Anyway, point here is to emphasise the change in the return type to : List<List<<String>> employeesDetails. Does it work this way ???.
(The question quoted above also has answers pointing to use Projections. I have questions about it but will post them on another question, don't want to mixup.)
I will list the points in the order you mentioned them:
The query has nothing to do with the POJO's field visibility. You are doing a simple query to the database, as if you were doing a query using SQL, and columns in a table have nothing to do with the fact that their mapped POJOs' fields in an application are public or private. The difference is only the language that you're using: now you're using the Hibernate Query Language (HQL), which allows you to express your query with respect to the POJOs' definitions instead of the database's tables' definitions. In fact, doing
session.createQuery("select empMaster.getName() from EmployeeMaster...");
will throw a syntax error: there can be no parenthesis in an object's field name.
By the way, you have to parse your query result to a String, otherwise there would be a compiler semantics error.
String name = (String) session.createQuery("select empMaster.name from EmployeeMaster...").setYourParameters().uniqueResult();
When you do a query whose SELECT clause contains more than one field, and you call uniqueResult(), you're obtaining an array of Objects (Object[]). You iterate through each element in the array and cast it to the corresponding type.
First of all, you probably forgot to add a .list() method call at the end of your query.
session.createQuery("select empMaster.name, empMaster.designation from EmployeeMaster").list();
Otherwise, the query will not be executed, and you would just have a QueryImpl object waiting to be triggered.
Now, when you're expecting multiple results in your query and selecting several fields, you're getting back a List<Object[]>. The elements of the list will be the array of fields for a specific record, and the array per se will be the fields.

SQL IN equivalent in DynamoDb in java

I have been given a task to return the data for a list of items whose ids I have. The table has an id defined as:
...
"KeySchema" [
0: {
"AttributeName":"id"
"KeyType":"HASH"
"TableStatus":"ACTIVE"
I have a list of say 100 of these ids and want to query to return the details in a similar way to how IN works in SQL.
I have tried many approaches but cant see a way I can make a single query to the DynamoDB instance where it will return all documents for the Ids in a supplied list.
I hope to use DynamoDBMapper.
I thought I'd hit the jackpot when I found withHashKeyValues on DynamoDBQueryExpression.
e.g.
DynamoDBQueryExpression<MyObject> ddqe;
...
for (String idStr : idList) {
MyObject mo= new MyObject();
mo.setId(idStr);
ddqe.withHashKeyValues(mo);
}
but looking at the code although the method is plural there is a note that says:
Note 1: Currently the DynamoDBMapper supports only one value per hash key.
I have also tried a Condition (amongst many other things)
Condition condition = new Condition();
condition.withAttributeValueList(filters);
condition.withComparisonOperator(ComparisonOperator.EQ);
Where filters is an ArrayList of the ids.
Is there a way to do this in DynamoDb or have I got to query the DB for every known id individually, e.g. issue 100 query's to the data store?
Queries start at a particular Partition key, so you would have to look up one key at a time with the Query API. Instead, you could use the BatchGetItem API and request 25 items a time.

solrj: how to store and retrieve List<POJO> via multivalued field in index

My use case is an index which holds titles of online media. The provider of the data associates a list of categories with each title. I am using SolrJ to populate the index via an annotated POJO class
e.g.
#Field("title")
private String title;
#Field("categories")
private List<Category> categoryList;
The associated POJO is
public class Category {
private Long id;
private String name;
...
}
My question has two parts:
a) is this possible via SolrJ - the docs only contain an example of #Field using a List of String, so I assume the serialization/marshalling only supports simple types ?
b) how would I set up the schema to hold this. I have a naive assumption I just need to set
multiValued=true on the required field & it will all work by magic.
I'm just starting to implement this so any response would be highly appreciated.
The answer is as you thought:
a) You have only simple types available. So you will have a List of the same type e.g. String. The point is you cant represent complex types inside the lucene document so you wont deserialize them as well.
b) The problem is what you are trying is to represent relational thinking in a "document store". That will probably work only to a certain point. If you want to represent categories inside a lucene document just use the string it is not necessary to store a id as well.
The only point to store an id as well is: if you want to do aside the search a lookup on a RDBMS. If you want to do this you need to make sure that the id and the category name is softlinked. This is not working for every 1:n relation. (Every 1:n relation where the n related table consists only of required fields is possible. If you have an optional field you need to put something like a filling emptyconstant in the field if possible).
However if these 1:n relations are not sparse its possible actually if you maintain the order in which you add fields to the document. So the case with the category relation can be probably represented if you dont sort the lists.
You may implement a method which returns this Category if you instantiate it with the values at position 0...n. So the solution would be if you want to have the first category it will be at position 0 of every list related to this category.

How to reuse a Criteria object with hibernate?

I'm trying to do query result pagination with hibernate and displaytag, and Hibernate DetachedCriteria objects are doing their best to stand in the way. Let me explain...
The easiest way to do pagination with displaytag seems to be implementing the PaginatedList interface that has, among others, the following methods:
/* Gets the total number of results. */
int getFullListSize();
/* Gets the current page of results. */
List getList();
/* Gets the page size. */
int getObjectsPerPage();
/* Gets the current page number. */
int getPageNumber();
/* Get the sorting column and direction */
String getSortCriterion();
SortOrderEnum getSortDirection();
I'm thinking of throwing my PaginatedList implementation a Criteria object and let it work along theese lines...
getFullListSize() {
criteria.setProjection(Projections.rowCount());
return ((Long) criteria.uniqueResult()).intValue();
}
getList() {
if (getSortDirection() == SortOrderEnum.ASCENDING) {
criteria.addOrder(Order.asc(getSortCriterion());
} else if (getSortDirection() == SortOrderEnum.DECENDING) {
criteria.addOrder(Order.desc(getSortCriterion());
}
return criteria.list((getPageNumber() - 1) * getObjectsPerPage(),
getObjectsPerPage());
}
But this doesn't work, because the addOrder() or the setProjection() calls modify the criteria object rendering it in-usable for the successive calls. I'm not entirely sure of the order of the calls, but the db throws an error on getFullListSize() trying to do a "select count(*) ... order by ..." which is obviously wrong.
I think I could fix this by creating an object of my own to keep track of query conditions and rebuilding the Criteria object for each call, but that feels like reinventing yet another wheel. Is there a smarter way, possibly copying the Criteria initially passed in and working on that copy?
Update:
It looks like getList is called first, and getFullListSize is called multiple times after, so, as soon as there's an ordering passed in, getFullListSize will fail. It would make sense to hit the db only once (in getList I'd say) and cache the results, with no need to copy/reset the Criteria object, but still...
Update (again):
Forget about that, once I've done the count I can't do the select, and vice versa. I really need two distinct Criteria objects.
Criteria.setProjection(null);
Criteria.setResultTransformer(Criteria.ROOT_ENTITY);
Will effectively "reset" the criteria between the rowCount projection and execution of the criteria itself.
I would make sure your Order hasn't been added before doing the rowCount, it'll slow things down. My implementation of PaginatedList ALWAYS runs a count query before looking for results, so ordering isn't an issue.
well, DetachedCriteria are Serializable, so you have built-in (if inelegant) deep clone support. You could serialize the initial criteria to a byte[] once on construction, then deserialize it each time you want to use it.
http://weblogs.asp.net/stefansedich/archive/2008/10/03/paging-with-nhibernate-using-a-custom-extension-method-to-make-it-easier.aspx
In that post I spotted a CriteriaTransformer.clone method.
That should copy the criteria object.
You can also set the projection on your getlist method.
Woops I didn't notice you were referring to java hibernate. Anyway, this http://forum.hibernate.org/viewtopic.php?t=939039
forum post should be able to answer your question.
Ugly as it may be I ended up using the serialization trick. I just serialize the DetachedCriteria object to a byte array on construction of the PaginatedList object and de-serialize it when needed. Ouch.
Another thing worth trying:
implement a generic DAO like the one suggested on hibernate's site and pass it to the PaginatedList object, along with a Restrictions object. The PaginatedList object would then do something like
Criteria.forClass(myDAO.getPersistentClass())
.add(myRestrictions)
.addOrder(<someOrder>)
and
Criteria.forClass(myDAO.getPersistentClass())
.add(myRestrictions)
.setProjection(Projections.rowCount());
Haven't tried that yet, but it should work.
There is a better and easy way to clone criteria, just simply:
ICriteria criteria = ...(your original criteria init here)...;
var criteriaClone = (ICriteria)criteria.Clone();
And getting back to Your problem. For pagination I've made a method, which gives me as a result:
1. Total rows count
2. Rows filtered by page & pageSize
In a single query to DB.
ICriteria criteria = ...(your original criteria init here)...;
var countCrit = (ICriteria)criteria.Clone();
countCrit.ClearOrders(); // avoid missing group by exceptions
var rowCount = countCrit
.SetProjection(Projections.RowCount()).FutureValue<Int32>();
var results = criteria
.SetFirstResult(pageIndex * pageSize)
.SetMaxResults(pageSize)
.Future<T>();
var resultsArray = results.GetEnumerable();
var totalCount = rowCount.Value;
public static DetachedCriteria Clone(this DetachedCriteria criteria)
{
var dummy = criteria.ToByteArray();
return dummy.FromByteArray<DetachedCriteria>();
}

Categories

Resources