Building a search criteria thats tricky? - grails

I am trying to do a search on my database IndividualRecords by first building a search criteria but its syntax is getting a little tricky for some values. Its easy to set a criteria for an exact field like if the firstName field has 'John' in it I would put this predicate in my criteria:
IndividualRecord.withCriteria {
if (predicates.firstName != null) {
eq 'firstName', predicates.firstName
}
}
But if they also add that they want to search for US citizens, I can't simply do,
if (predicates.UScitizenship) {
eq 'citizenship', predicates.citizenship
}
because I want to look for records based on citizenship 'US', 'Us', 'uS', and 'us'(case insensitivity must be taken in to account) so how would I get around this?
and then here is where the real fun starts. Say I want to find only foreign citizens. I do have a low level mongodb api method that tells me if the citizenship is a valid one by returning true if it finds it in the database of country codes that I have so I guess I could build another predicate something like pseudocode:
if (predicates.foreign) {
all such people whose !citizenship.caseIgnoreEquals('US') && matchCountry(it.citizenship)
}
meaning that all such people whose citizenship isn't 'US' and matches the list of country codes I have where matchCountry(String countryCode) is my low level api method for verifying a country code and will return true if its a valid country code.
I am finding it hard to define such complicated predicates' syntax and that is where I need some help. Thanks.

There are two issues at hand here.
First, case sensitivity and insensitivy can be addressed by using ilike instead of equals. So for example:
if (predicates.firstName != null) {
ilike 'firstName', predicates.firstName
}
Secondly, you may want to look at named queries to encapsulate some of your query definitions. This way you can include/exclude them as you see fit. For example:
if (predicates.foreign) {
foreignPersons(predicates) // call to named query which contains logic
}
Using this you should be able to construct very complex queries which are built upon smaller definitions and in turn make them more usable and reusable.

Related

Grails criteria duplicate association path error

I am trying to use aliases along with the normal association names in a criteria which is giving me "duplicate association path error" my classes are as follows
class FlightReservation{
Flight flight
User usr
String title
}
class Flight {
String flightNumber
Category category
}
class Category {
String name
}
Criteria query
FlightReservation.createCriteria().list(){
createAlias("flight", "flt", CriteriaSpecification.LEFT_JOIN)
flight{
location{
eq("name", "abc")
}
}
order("flt.flightNumber", "asc")
}
Now as i think about it, it seems obvious and perhaps a Hibernate limitation
so i want to know if there's an alternate approach to achieve this
I know i can use fetchMode to load the flight association
but eliminating alias from the query would make things difficult for order clause( which is going to be dynamic and nesting closures would make things ugly)
One might say why can't I use "flt" (alias) in both the places? Actually this other criteria which uses the nested closure instead of alias comes from some other part of the code and I am supposed to reuse that code.
Let me know, if the question isn't clear enough, any insights on this error would be really helpful.

GORM/Grails :: possible to query based on contents of a List within the model?

Assume the following:
class Thing {
String name
List<String> tags
static constraints = {
name(nullable: false)
tags(nullable: false)
}
}
I want to know if its possible, using GORM, to run a query for domain instances based on values in their respective lists
For instance: Are there dynamic GORM finders to query things like 'Find all Things that have the tag "Video" ', or 'Find all things with name = "Product1" that have the tag "Image" '
Just want to know if there's a nice concise way of doing this with Grails&Gorm, as opposed to retrieving a list of Things and iterating through it, finding the ones that have the appropriate tags and adding them to a results list.
Thanks!
One way (although not necessarily the most efficient!) would be to return the whole list of Things eg Thing.list() and then filter the resulting list using findAll.
List results = Thing.list().findAll{it.tags.contains("Image")}
How big is your list of Things and associated Tags likely to be?

Avoiding subqueries in HQL using Grails

I have two object, a room type and a reservation. Simplified they are:
class Room {
String description
int quantity
}
class Reservation {
String who
Room room
}
I want to query for all rooms along with the number of rooms available for each type. In SQL this does what I want:
select id, quantity, occupied, quantity-coalesce(occupied, 0) as available
from room left join(select room_id, count(room_id) as occupied from reservation)
on id = room_id;
I'm not getting anywhere trying to work out how to do this with HQL.
I'd appreciate any pointers since it seems like I'm missing something fairly fundamental in either HQL or GORM.
The problem here is your trying to represent fields that are not your domain classes like available and occupied. Trying to get HQL\GORM to do this can be a bit a little frustrating, but not impossible. I think you have a couple options here...
1.) Build your domain classes so that there easier to use. Maybe your Room needs to know about it's Reservations via a mapping table or, perhaps write what you want the code to look like and then adjust the design.
For example. Maybe you want your code to look like this...
RoomReservation.queryAllByRoomAndDateBetween(room, arrivalDate, departureDate);
Then you would implement it like this...
class RoomReservation{
...
def queryAllByRoomAndDateBetween(def room, Date arrivalDate, Date departureDate){
return RoomReservation.withCriteria {
eq('room', room)
and {
between('departureDate', arrivalDate, departureDate)
}
}
}
2.) My second thought is... It's okay to use the database for what it's good for. Sometimes using sql in you code is simply the most effective way to do something. Just do it in moderation and keep it centralized and unit tested. I don't suggest you use this approach because you query isn't that complex, but it is an option. I use stored procedures for things like 'dashboard view's' that query millions of objects for summary data.
class Room{
...
def queryReservations(){
def sql = new Sql(dataSoruce);
return sql.call("{call GetReservations(?)}", [this.id]) //<-- stored procedure.
}
}
I'm not sure how you can describe a left join with a subquery in HQL. INn any case you can easily execute raw SQL in grails too, if HQL is not expressive enough:
in your service, inject the dataSource and create a groovy.sql.Sql instance
def dataSource
[...]
def sql= new Sql(dataSource)
sql.eachRow("...."){row->
[...]
}
I know it's very annoying when people try to patronize you into their way of thinking when you ask a question, instead of answering your question or just shut up, but in my opinion, this query is sufficiently complex that I would create a concept for this number in my data structure, perhaps an Availability table associated to the Room, which would keep count not only of the quantity but also of the occupied value.
This is instead of computing it every time you need it.
Just my $.02 just ignore it if it annoys you.

MyEntity.findAllByNameNotLike('bad%')

I'm attempting to pull up all entities that have a name that doesn't partially match a given string.
MyEntity.findAllByNameNotLike('bad%')
This gives me the following error:
No such property: nameNot for class: MyEntity
Possible solutions: name" type="groovy.lang.MissingPropertyException">
I had a quick look at the criteria style but I can't seem to get that going either,
def results = MyEntity.withCritieria {
not(like('name', 'bad%'))
}
No signature of method: MyEntity.withCritieria() is applicable for argument types: (MyService$_doSomething_closure1)
Ideally I would like to be able to apply this restriction at the finder level as the database contains a large number of entities that I don't want to load up and then exclude for performance reasons.
[grails 1.3.1]
I've worked out how to do this using withCriteria, the not should have been a closure of its own.
def results = MyEntity.withCritieria {
not {
like('name', 'bad%'))
}
}
The problem I initially had using withCriteria was that I was trying to test this as a unit test, which works fine with the dynamic finders, but not with the criteria API (as far as I can tell).
(I'll leave this unanswered for a day to see if anyone has a better solution, otherwise I'll accept my answer)

Repository Interface - Available Functions & Filtering Output

I've got a repository using LINQ for modelling the data that has a whole bunch of functions for getting data out. A very common way of getting data out is for things such as drop down lists. These drop down lists can vary. If we're creating something we usually have a drop down list with all entries of a certain type, which means I need a function available which filters by the type of entity. We also have pages to filter data, the drop down lists only contain entries that currently are used, so I need a filter that requires used entries. This means there are six different queries to get the same type of data out.
The problem with defining a function for each of these is that there'd be six functions at least for every type of output, all in one repository. It gets very large, very quick. Here's something like I was planning to do:
public IEnumerable<Supplier> ListSuppliers(bool areInUse, bool includeAllOption, int contractTypeID)
{
if (areInUse && includeAllOption)
{
}
else if (areInUse)
{
}
else if (includeAllOption)
{
}
}
Although "areInUse" doesn't seem very English friendly, I'm not brilliant with naming. As you can see, logic resides in my data access layer (repository) which isn't friendly. I could define separate functions but as I say, it grows quite quick.
Could anyone recommend a good solution?
NOTE: I use LINQ for entities only, I don't use it to query. Please don't ask, it's a constraint on the system not specified by me. If I had the choice, I'd use LINQ, but I don't unfortunately.
Have your method take a Func<Supplier,bool> which can be used in Where clause so that you can pass it in any type of filter than you would like to construct. You can use a PredicateBuilder to construct arbitrarily complex functions based on boolean operations.
public IEnumerable<Supplier> ListSuppliers( Func<Supplier,bool> filter )
{
return this.DataContext.Suppliers.Where( filter );
}
var filter = PredicateBuilder.False<Supplier>();
filter = filter.Or( s => s.IsInUse ).Or( s => s.ContractTypeID == 3 );
var suppliers = repository.ListSuppliers( filter );
You can implement
IEnumerable<Supplier> GetAllSuppliers() { ... }
end then use LINQ on the returned collection. This will retrieve all suppliers from the database that are then filtered using LINQ.
Assuming you are using LINQ to SQL you can also implement
IQueryable<Supplier> GetAllSuppliers() { ... }
end then use LINQ on the returned collection. This will only retrieve the necessary suppliers from the database when the collection is enumerated. This is very powerful and there are also some limits to the LINQ you can use. However, the biggest problem is that you are able to drill right through your data-access layer and into the database using LINQ.
A query like
var query = from supplier in repository.GetAllSuppliers()
where suppliers.Name.StartsWith("Foo") select supplier;
will map into SQL similar to this when it is enumerated
SELECT ... WHERE Name LIKE 'Foo%'

Resources