Grails table-per-subclass inheritance and discriminator - grails

I am using Domain inheritance in grails App with
tablePerHierarchy false
So i get one big table with common properties and for each subclasses tables with specific columns to them only.
So let say relation is like below
A -> B
A -> C
A -> D -> E
A -> F -> G
where A is parent class. Now i need to find all B,D,E and need to have paged results on that. I was trying to write criteria query but as no discriminator support is there. Can anyone help me out on the same?
I have tried to use following criteria query and found one strange thing.
A.createCriteria().list(max:max,offset:offset) {
eq("isDeleted", false)
inList('class', [1,3])
}
It worked for me but one strange thing. How would i identify which class is referring to value 1 as discriminator and which to value 2?
I am on Grails 2.4.2

Related

How do I create a Grails query for a many-to-many using primitives?

I have a POGO we'll call Foo and it has a list of Bars. In the database, these are simple integers, but they're stored in a separate table (Foo_Bars)
class Foo {
String name
...
static hasMany = [bars:Integer]
...
}
So my question is, how do I create a query to find all Foos that with bars that are in a list. I know how I would write it in SQL.
SELECT * FROM foo, foo_bars
WHERE foo.id = foo_bars.foo_id
AND foo_bars.bars_integer IN (11, 15, 52)
But I figure there must be a simpler way, using GORM or HQL. How would I write this?
but what exactly you want to achieve? list of Foo's where bars is equal to (11,15,52), or ONE OF bars is in the list or the list of bars contain each of given list?
either way, I doubt you can do it in criteria or using a dynamic finder, I'm trying to do it in an unit test and nothing worked
I would go with creating another domain class like
class FooBar {
Foo foo
Integer integer
}
which would create exactly the same database table as you already have, and then querying would be much simpler

customising GORM basic collections

As well as associations between different domain classes, GORM also supports mapping of basic collection types. . For example, the following class creates a nicknames association that is a Set of String instances
class Person {
static hasMany = [nicknames:String]
}
This will store the nicknames in a separate table person_nicknames:
---------------------------------------------
| person_id | nickname |
---------------------------------------------
| 1 | Fred |
---------------------------------------------
By default both columns are nullable and there are no indices present. I would like to make the following changes
make both columns not null
put a composite unique index on (person_id, nickname)
Obviously I could just run an SQL script to make these changes, but is it possible for me to express this in the domain model, so that GORM does it when creating and updating the schema?
No, this presently isn't possible. You can fake it by making Nickname an explicit domain class (Andre Steingress gives an example in the question comments), but otherwise you have to write a migration.
You can use joinTable and basic collection types.
http://grails.org/doc/2.4.3/ref/Database%20Mapping/joinTable.html
You can specify SQL behavior with column mapping:
http://grails.org/doc/2.4.3/ref/Database%20Mapping/column.html

grails gorm hasMany query based on select options from a gsp page

I have the following scenario,
Domain class A which hasMany B's
Domain class B which hasMany C's and belongsTo A
Domain class C which belongsTo B
Class E {
A a
B b
C c
}
Class C {
String name
}
I want to query E values i.e get a list of some E property eg in this case c.name based on values selected by a user in a select box, i.e user selects A and B from multiple select boxes and based on this criteria, a list of names is obtained.
in other words i want to find all names in c which satisfy condition set by a and b
have tried to figure out the GORM query to no avail.
thanks
I solved this by using raw SQL joins. Not really certain if this was the best way but it worked for me.
I got the parameters from A and B, ie
def fromA = params.someCriteriaValueInA
def fromB = params.someCriteriaValueInB
Please note that these are fetched from a gsp. Also, fromB values would be loaded based on fromA values, using chained selects.
In the grails controller/service ...
def db = new Sql(dataSource)
def result = db.rows("your sql to go here")
Then you can do whatever you want with the results, for example manipulate it in a template
render(template: "myResults", model:[result :result])
Dont forget to inject the dataSource bean in your controller/service, and also doing the necessary import
import groovy.sql.Sql
Please note that this involved traversing many domain class instances, and for those who like raw SQL this would seem easier.Would appreciate a different approach, maybe using GORM's criteria.

How to define what DatabaseGenerated.Computed should compute?

I am just doing my first steps with EF CodeFirst, especially with dataAnnotations.
Now I'm doing my best to understand the "DatabaseGenerated" attribute.
What I know so far:
using this attribute gives me three options to handle creation of a property value: Computed, Id and None.
using this attribute means, that the property can not be updated manually - it is done by the database
So - as I can imagine what happens when using th "Id" option, I have no idea what happens when using "Computed" option. I red that this should tell the db to compute the field value.
For example: field "sum" = field "price" + field "shipping".
But how can I use that in that way? I looked around and did not find any examples. Could you please help me?
You can't use EF to tell the database how to compute the column -- you can only tell EF that the column is database generated so it should be retrieved from the database for your use in code.
To control how the database computes the column you have to manually instruct it either outside of EF or in your database initialization logic.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
context.Database.ExecuteSqlCommand("RAW SQL HERE");
}
Your SQL (MS T-SQL) might look like this (more here):
CREATE TABLE t2 (a int, b int, c int, x float,
y AS CASE x
WHEN 0 THEN a
WHEN 1 THEN b
ELSE c
END)
For SQL here's some info about Computed Colums:
http://msdn.microsoft.com/en-us/library/ms191250(v=sql.105).aspx
Also for reference:
http://msdn.microsoft.com/en-us/library/gg193958.aspx

F# -> Seq to Map

I'm trying to load all my Categories from the database and then map them to a Map (dictionary?), however when I use the following code:
[<StructuralComparison>]
type Category = {
mutable Id: string;
Name: string;
SavePath: string;
Tags: ResizeArray<Tag> }
let categories = session.Query<Category>()
|> Seq.map(fun z -> (z,0))
|> Map.ofSeq
it simply throws an error that says:
The struct, record or union type
'Category' has the
'StructuralComparison' attribute but
the component type 'ResizeArray'
does not satisfy the 'comparison'
constraint
I have absolutely no clue about what to do, so any help is appreciated!
F# is rightly complaining that ResizeArray<_> doesn't support structural comparison. ResizeArray<_> instances are mutable and don't support structural comparison, and you therefore can't use them as fields of records which are used as keys to Map<_,_>s (which are sorted by key). You have a few options:
Have Tags use a collection type that does support structural comparison (such as an immutable Tag list).
Use [<CustomComparison>] instead of [<StructuralComparison>], which requires implementing IComparable.
Use a mutable dictionary (or another relevant collection type) instead of a Map. Try using the dict function instead of Map.ofSeq, for instance.
The problem here is that by adding StructuralComparison attribute to the type Category you've asked F# to use structural comparison when comparing instances of Category. In short it will compare every member individually to see if they are equal to determine if two instances of Category are equal.
This puts an implicit constraint on every member of Category to themselves be comparable. The type ResizeArray<Tag> is generating an error because it's not comparable. This is true for most collection types.
In order to get rid of this error you'll need to make the ResizeArray<T> type comparable or choose a different key for the Map. Don has a great blog post that goes into this topic in depth and provides a number of different ways to achieve this. It's very much worth the read
http://blogs.msdn.com/b/dsyme/archive/2009/11/08/equality-and-comparison-constraints-in-f-1-9-7.aspx

Resources