Grails - Adding a where clause to all domain objects - grails

We have a Grails application that connects to a legacy database in which every table has a column called deleted which indicates if an entity has been deleted or not (this means data never actually gets deleted from the table, it gets archived after a certain amount of time). For each of our domain objects we would like to add an automatic where clause that looks like:
where deleted = false
so that we do not have to add this explicitly to every query within the application. Is there a way to achieve this in grails?

I use the Hibernate Filter plugin for these kinds of things.

I don't think that GORM supports this directly. However, you can take advantage of the hibernate interceptor and add it yourself. In particular, you can use the onPrepareStatement hook to add the where clause to each query that hibernate generates. For example:
// src/groovy/mypackage/MyEntityInterceptor.groovy
package mypackage
class MyEntityInterceptor extends org.hibernate.EmptyInterceptor {
String onPrepareStatement(String sql) {
return addNotDeletedClause(sql)
}
}
// grails-app/conf/spring/resources.groovy
beans = {
entityInterceptor(MyEntityInterceptor)
}
Unfortunately, you'll have to parse the incoming SQL statement to figure out where to insert the where clause.

Related

Grails findAll not finding values in a set

I've got a domain called Planning that has a hasMany of another domain called Employee included in it. I'm trying to do a findAll of these plannings where the plannings contain a particular employee and I can't get it to work.
I'm trying to do it like so, my print statements do print the contains as true
plannings = plannings.findAll{planning->
if(employee) {
log.info("find plannings with employee ${employee} ${planning.employees.contains(employee)}")
planning.employees.contains(employee)
}
}
I'm not doing this as a Hibernate query as this broke the application in another weird way. This code is executed in a for each and for whatever reason that causes some weird behavior with Hibernate.
The closure must return a boolean value - see http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Collection.html#findAll(groovy.lang.Closure)
This should work (not tested):
plannings = plannings.findAll{planning-> planning.employees?.contains(employee)}
BTW: I wouldn't assign the filtered list to the origin plannings list. Extract a a new expressive variable like planingsOfEmployee or something similar.
Without more relevant details around your problem (what's the weird behavior? log traces? hibernate mappings?, etc.) all we can do is to speculate; and if I have to do so, I would say that most likely:
The employee object you are using for comparison is a detached one.
The employee object does not override meaningfully equals and hashCode
You use using this detached employee to do comparisons against against persisted employees (using planning.employees.contains(employee)) found inside planning
Under these circumstances the comparisons will never be true even when they may represent the same objects. If this is your case, you must either:
Use a persisted employee object to do the comparisons.
Or, implement equals and hashCode semantically meaningful for Employee
Hope this helps.

Does it matter what Domain Object you execute a query on in grails

Does it matter what domain object you use when you execute a query? For instance, I have these two domain objects
Class A {
String name
}
Class B {
String name
}
If I want to get all A objects, I can do the following
A.executeQuery('FROM A')
But I can also call the same query from a different domain object and get the exact same results as so
B.executeQuery('FROM A')
Is there a difference between these two statements performance wise? Maybe something under the hood that is happening differently?
For a little more context, I am writing a service where the application will be executing queries off of domain objects dynamically. So I could either pick a base domain object and just execute off that every time, or I can maybe make an instance of the domain object with a string that is provided into the method.
Thanks
No, it does not matter. In this case it's just executing HQL (hibernate query) and either domain class acts exactly the same in this respect for executeQuery.
In your specific case I'd just use a single domain class to execute all the queries from. No need to change the type.
Does it matter what domain object you use when you execute a query?
It depends on what query technique you are using. For executeQuery in particular it does not. For most other query techniques it does. For example, A.executeQuery('FROM A') is the same as B.executeQuery('FROM A'). A.list() is not the same as B.list(). A.findAllByTitle('Tribe') is not the same as B.findAllByTitle('Tribe'), A.where { ... } is not the same as B.where { ...}, etc...

EF Code first database/table initialization - WHEN does it happen?

My application is using EF code-first design and all generally works very well.
Via a private configuration file, I can specify how I would like EF to handle changes to the db schema, and so create/recreate the relevant tables as desired - the options are "never" "create", "always", "onSchemaChanged" and (for the future) "onSchemaModified".
This works well - but I am getting lost in a couple of places .....
During development, I would like to use the hook as described in
"Database in use error with Entity Framework 4 Code First" - but this seems to execute on EVERY run of my program"
public void InitializeDatabase(Context context)
{
context.Database.SqlCommand("ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
_initializer.InitializeDatabase(context); // Maybe this does nothing if not needed
context.Database.SqlCommand("ALTER DATABASE Tocrates SET MULTI_USER")
}
So .. to real my question: Is there an override that I can use to detect whether EF will ACTUALLY be trying to modify the database, so I can set this SINGLE_USER stuff when needed? And if so, can I detect the reason EF it is doing so (see my list of options above) so I can log the reason for change?...
All help and suggestions are very much appreciated.
Unless you have set the database intializer to null initializers run always once (per application lifetime) when you are using a context for the first time. What then actually happens depends on the initializer (your inner _intializer):
For DropCreateDatabaseAlways and CreateDatabaseIfNotExists it's clear by their name what they do.
For DropCreateDatabaseIfModelChanges there is only the question if the model changed or not. EF detects this by comparing a model hash with a hash stored in the database. You can check this yourself by calling...
bool compatible = context.Database.CompatibleWithModel(true);
...within your custom InitializeDatabase and then decide based on the result if you want to send your SqlCommands or not. (Don't call this with a self-created context because it will cause the database to be intialized first before the model compatibilty is checked.) The parameter bool throwIfNoMetadata (which is true in my example) causes EF to throw an exception if the model hash in the database does not exist. Otherwise the method will return true in that case.
For a custom inner initializer: Whatever your code will do.

How do I avoid automatic schema modifications when working with legacy databases using Grails?

Grails does automatic schema modifications (including index/foreign key updates) when changing the domain model. This is usually fine, but when working with legacy databases I would like to completely disable all table modifications.
How do I instruct Grails never to modify the table structure (including indexes and foreign key constraints)?
This is how I've currently setup the mapping:
class ClassName {
String string1
String string2
AnotherClass anotherClass
static mapping = {
version(false)
table("legacy_table")
string1(column: "some_legacy_field_1")
string2(column: "some_legacy_field_2")
anotherClass(column: "another_class_id", nullable: true, ignoreNotFound: true)
}
}
The dataSource defined in /grails-app/conf/DataSource.groovy has a dbCreate property, which can be set to validate to check that the schema matches the domain model without changing it in any way.
More details here:
http://grails.org/doc/latest/guide/3.%20Configuration.html#3.3%20The%20DataSource
As mentioned before, the property dbCreate is the one you use to specify how the database would be altered every time there are changes done in the Domain classes. I would suggest removing this property entirely as Burt suggested, so Hibernate does not control how the database is updated since that could cause certain conflicts depending on the changes you make to your domain classes.
The way I manage the database changes in our project is by using a database migration, I recommend using Liquibase, there is plug in for Grails that works perfectly, it is easy to use and offer great flexibility.

Is it possible to use a JNDI dataSource read only in Grails?

I need to add a JNDI datasource from a legacy database to my Grails (1.2.2) application.
So far, the resource is added to my Tomcat (5.5) and DataSource.groovy contains:
development {
dataSource {
jndiName = "jdbc/lrc_legacy_db"
}
}
I also created some domain objects mapping the different tables to comfortably load and handle data from the DB with GORM. But I now want to assure, that every connection to this DB is really read-only. My biggest concern here is the dbCreate- property and the automatic database manipulation through GORM and the GORM classes.
Is it enough to just skip dbCreate?
How do I assure that the database will only be read and never ever manipulated in any way?
You should use the validate option for dbCreate.
EDIT: The documentation is quite a bit different than when I first posted this answer so the link doesn't quite get you to where the validate option is explained. A quick find will get you to the right spot.
According to the Grails documentation:
If your application needs to read but never modify instances of a persistent class, a read-only cache may be used
A read-only cache for a domain class can be configured by
1. Enable Caching
Add something like the following to DataSource.groovy
hibernate {
cache.use_second_level_cache=true
cache.use_query_cache=true
cache.provider_class='org.hibernate.cache.EhCacheProvider'
}
2. Make Cache Read-Only
For each domain class, you will need to add the following to the mapping closure:
static mapping = {
cache usage:'read-only', include:'non-lazy'
}

Resources