Grails Criteria query with a condition on data - grails

I have a database table storing data for this Grails domain class using vanilla GORM:
class A {
String propOver // may be null
String propBase
}
I want to create a search query that searches against the propOver property if it contains a value, otherwise against the propBase property. Or, to word this differently, propOver overrides propBase when it exists.
I need something that works like this pseudo-code:
def results = A.createCriteria().list{
if propOver isn't null: // the heart of the problem
eq('propOver', search_input)
else
eq('propBase', search_input)
}
Is it even possible?
Please note that one (bad) solution would be to create a 3rd property that stores the propOver ?: propBase value, but it violates the DRY principle, and I'd prefer avoiding modifying the DB.

This will do?
A.createCriteria().list{
or {
eq 'propOver', search_input
and {
isNull 'propOver'
eq 'propBase', search_input
}
}
}

Related

Trim domain field by default

What is the best way to trim field value in domain?
My suggestion is to use beforeSave(), but would work something like this?
class Book {
String name = name?.trim()
}
You have a couple options depending on what behavior you want.
A custom setter, which will trim the value every time you set it
class Book {
String name
void setName(String name) {
this.name = name?.trim()
}
}
A custom getter, which will give you a trimmed value but not store it in the database
class Book {
String name
String getName() {
this.#name?.trim()
}
}
A hibernate event, like beforeSave() as you mentioned, which will only trim it before the object is persisted.
Well, you can enable automatic trimming of string in Grails (version 2.3+) by setting below property in Config.groovy file:
grails.databinding.trimStrings = true
This will automatic trim the string before save or update.
I have have noticed that Grails automatically does a .trim() on fields before persisting them. For example:
null
""
" "
All gets stored as null in Grails 2.3.7 for a nullable string. In addition:
" foobar "
gets stored as "foobar"
These results are using the default h2 database. So you might let Grails do the heavy lifting in this case.
Here is my hack for quickly trimming all fields in a domain object. I often receive JSON data that is not formatted in a way that would allow me to use data-binding techniques. This method can be called after updating or assigning all values in the domain instance.
class Book {
def trimFields() {
this.properties = this.properties
}
}
Requires this configuration which is set by default in Grails
grails.databinding.trimStrings = true
I know this is overkill but it's quick and easy to add to a domain class.

Dapper.NET mapping with Data Annotations

So I have a class with a property like this:
public class Foo
{
[Column("GBBRSH")
public static string Gibberish { get; set;}
....
}
For saving data, I have it configured so that the update/insert statements use a custom function:
public static string GetTableColumnName(PropertyInfo property)
{
var type = typeof(ColumnAttribute);
var prop = property.GetCustomAttributes(type, false);
if (propr.Count() > 0)
return ((ColumnAttribute)prop.First()).Name;
return property.Name;
}
This handles fine, but I noticed that when I go to retrieve the data, it isn't actually pulling data back via the function for this particular column. I noticed that the other data present was pulled, but the column in question was the only field with data that didn't retrieve.
1) Is there a way to perhaps use the GetTableColumnName function for the retrieval part of Dapper?
2) Is there a way to force Dapper.NET to throw an exception if a scenario like this happens? I really don't want to have a false sense of security that everything is working as expected when it actually isn't (I get that I'm using mapping that Dapper.NET doesn't use by default, but I do want to set it up in that manner).
edit:
I'm looking in the SqlMapper source of Dapper and found:
private static IEnumerable<T> QueryInternal<T>(params) // my knowledge of generics is limited, but how does this work without a where T : object?
{
...
while (reader.Read())
{
yield return (T)func(reader);
}
...
}
so I learned about two things after finding this. Read up on Func and read up on yield (never used either before). My guess is that I need to pass reader.Read() to another function (that checks against column headers and inserts into objects appropriately) and yield return that?
You could change your select statement to work with aliases like "SELECT [Column("GBBRSH")] AS Gibberish" and provide a mapping between the attribute name and the poco property name.
That way, Dapper would fill the matching properties, since it only requires your POCO's to match the exact name of the column.

Grails createCriteria: finding objects via a field that is a null domain class instance

I'm seeing some unexpected behavior in Grails' createCriteria. I have a domain class that looks like this:
MyDomainClass {
AnotherDomainClass anotherDomainClass
static constraints = {
anotherDomainClass(nullable:true)
}
}
I want to find all instances of MyDomainClass where anotherDomainClass is null. So I do this:
return MyDomainClass.createCriteria().list {
eq('anotherDomainClass', null)
}
However, I get nothing back.
What am I doing wrong? I can see there are database entries where the ANOTHERDOMAINCLASS_ID column is indeed null (or blank, I can't tell).
I'd be fine creating a query that references the ANOTHERDOMAINCLASS_ID column directly, but I haven't found a way yet.
Thanks!
Instead of using eq you can use the isNull
def results = MyDomainClass.withCriteria {
isNull('anotherDomainClass')
}
Here's a good reference HibernateCriteriaBuilder Javadoc too.
What happens if you try isNull instead of eq?
EDIT: Could actually be isEmpty instead of isNull.
It's not a real answer, but my workaround for the time being is to retrieve all the objects from the database and filter in the app tier, like this:
MyDomainClass.list({it.anotherDomainClass == null})

grails findAll tag

How to use "SELECT id, name, part, description FROM user " in grails findAll tag.
I tried
User.findAll("SELECT id, name, part, description FROM user")
instead using
User.findAll("FROM user")
But shows errors.
What is the tag?
finadAll() returns a Collection of domain objects, so enumerating columns to select does not make sense; the queries it understands are not real SQL, and consist basically only of WHERE clauses. Since you don't seem to want to constrain the result set, this is probably all you need:
User.findAll()
It will return a collection of all User objects. If you need constraints, the syntax ist
User.findAll("from User as u where u.id=?", [userId])
Or, even simpler, you can use a dynamic finder:
User.findAllById(userId);
If you want to run report-style queries like this, use the executeQuery method:
def rows = User.executeQuery("SELECT id, name, part, description FROM User")
The return value will be a List of Object[] where each element in the object array is the type of the column, i.e. the 1st element will be a long, 2nd a String, etc.
Note that User has to be capitalized since you're referring to the Hibernate entity - this isn't a SQL query, it's HQL.
If you want to query for only certain fields, you can use a criteria query with a projection.
Example:
def userProperties = User.withCriteria {
projections {
property('id')
property('name')
property('part')
property('description')
}
}
This query will return an array of Strings (or whatever the database column type is mapped to) for each matching row, instead of a domain object.
It will return an ArrayList of objects you only have to access that objects values. For example:
def result = Code.findAll("from Code as c where c.user_code=?",[pass])
result[0].user_code
Where my Code class is something like this:
class Code {
String user_code
boolean flg_active
static constraints = {
user_code nullable:true, blank:true, size:0..Text.MID
flg_active nullable:true, blank:true, default:1
}
}

Default Values in LINQ Modelling

To put it in basic form, my database table doesn't allow nulls for varchars, it must have blanks. My model doesn't allow nulls so it won't insert a record if I leave form fields empty. If an empty form field appears I want a default value of blank to be used instead. I've tried, for example, the following without any luck:
[Column]
[DisplayName("WMD Company")]
[DefaultValue(" ")]
public string WMDCompany { get; set; }
So instead, in my controller action I have to do a check like the following:
if(myModel.WMDCompany == null) myModel.WMDCompany = " ";
Which is plain nasty to me. Is there any way of getting [DefaultValue(" ")] to work?
Cheers
What about something like this:
private string wmdCompany;
public string WMDCompany
{
get
{
if (this.wmdCompany == null)
{
return string.Empty;
}
return this.wmdCompany;
}
set
{
this.wmdCompany = value;
}
}
The DefaultValue attribute is not used. LINQ to SQL has not support for DB defaults unfortunately. That property is intended for use in API extension if I remember, but I don't know of any that use it.
Two approaches to get around this you could use.
First update your data layer, by appropriately controlling the property, and setting it to null. Use a partial class to extend your data class, and implement the OnCreated() partial method, and in this set the value to String.Empty.
partial void OnCreated()
{
MyProp = String.Empty;
}
Secondly, you could change your DBML representation to allow nulls, but in your database, use a trigger to convert NULLs to empty strings.
I'd go with the first approach myself - assuming you can't just use NULLs as suggested by Adrian
Inserting spaces as a placeholder for NULL seems like a very obscure method to me. Why don't you just change your table design to allow NULL values?

Resources