Problems with deleting objects in Grails - slow, and still not really deleted - grails

This is probably a rookie mistake, so forgive me in advance. I have searched high and low for a solution, but without result - so I thourght I'd add my first post here :-)
I have two domain classes, one called Domain and one called Page. As below code shows, the Domain has many Page(s).
class Domain {
...
static hasMany = [ pages : Page, ... ]
static mapping = {
pages lazy:true
}
}
class Page {
String identifier
...
static belongsTo = [ domain : Domain ]
static hasMany = [ ... ]
static constraints = {
identifier(blank:false, unique:'domain')
}
static mapping = {
...
domain lazy:true
}
}
My application has a long algorithm that amongst other things creates Pages on a Domain. If you run the algorithm with the same arguments as a previous run, it will start by deleting all pages created by the previous run before running the algorithm again.
I have two problems:
Problem #1
When I delete a specific Page from a Domain using:
def domain = page.domain
domain.removeFromPages(page);
page.delete()
domain.save(flush:true)
This causes Hibernate to fetch and load all pages of the domain, which ultimately fires several thousands queries (the domain has MANY pages). How am I improving perfomance on this? - Executing sql directly to delete the page make the database and hibernate get out of sync.
Problem #2
When I later create the page again:
def page = new Page(identifier:'...').save(failOnError:true)
I get the:
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session
Any help is welcome - I am losing my mind here :-/

I would suggest to think about a small redesign of your classes.
First, remove the pages-collection from "Domain"
Class Domain {
// no pages here
}
And then put a simple reference to "Domain" in "Page"
Class Page {
String identifier
Domain domain
...
}
This makes the handling of your pages much easier.
I don't know if this is really an option for you because you have to make changes to your existing code, but it can save you a lot of trouble with your large collections. There is also a presentation by Burt Beckwith about this.

For a batch delete, see this post by the IntelliGrape
I had to fetch and store holidays stored in a remote system, and on each fetch delete the ones I had stored locally and this came up like this:
Holiday.list()*.delete(flush:true)
The * is where all the magic happen. Note that you can restrict the number of items to delete with the list() method.
On a batch, note that you can also use the following to perform a batch.
def session = sessionFactory.openSession()
def tx = session.beginTransaction()
...
for(holiday in holidays) {
def h = new Holiday(..)
session.save(h)
}
sessionFactory.currentSession.flush()
tx.commit()

Related

Override getter in grails domain class for relation version issues

I have an existing application with the following domain classes/relations:
class Contact {
static hasMany = [phones: Phone]
}
I would like to modify the structure to allow for a delete flag to be set in the Phone class and then not have to modify existing calls to the getter for phones to get phones that have not had that delete flag set.
ex:
contact.phones
I have seen a post on this site detailing how to do this.
StackOverflowPost
I have tried that approach(modifications showed below) but GORM is behaving oddly by incrementing the version when it shouldn't be. I'll hit the contact edit page and then when a version comparison is done on the server after submitting the form the version in the DB has incremented up about 5 or 6 times compared to the version value that was passed to the edit.gsp. I have also applied this pattern to two more relations so I'm thinking they are also causing the version to increment. I'm going to test with only one domain relation modification to see if I can find a pattern. Does anyone have any ideas as to the right way to do this or how to avoid version incrementing?
class Contact {
Set<Phone> phones
static hasMany = [phones: Phone]
Set<Phone> getPhones() {
phones.findAll { !it.deleted }
}
}
Not a direct answer to your question, but i use methods in my class, which instead of returning the actual domain instances, returns the detached criteria that callers can use, add new restrictions, and finally get the results.
​class Contact {
DetachedCriteria<Phone> phones() {
def criteria = new DetachedCriteria(Phone).build {
eq "deleted", false
eq "contact", this
}
return criteria
}
}​
The contact class will return a criteria with main restrictions added, and callers can add more restrictions if they have to.
List phones = contact.phones().list()
or
List phones = contact.phones().list {
eq "country", "xxx"
}
This gives callers more flexibility.

Set a Grails Domain Class as "No-Insert Mode"

I need to use a complex query on my Grails application. Instead of using a complex criteriaBuilder(), I instead performed the following:
Created View on the database, say ParentChildView.
Mapped it into a domain class.
Use this ParentChildView domain class to perform a .list() operation.
I'm wondering if I can configure this domain class to something like "select-only mode" or "no-insert-allowed mode"?— you know, just to make sure an Exception will be thrown if some developer accidentally tries to insert to this domain.
As per my understanding of your question, you don't want insertion to happen or for sure updates as well.
Your action could be one from these.
User meta-programming and make save method throw an exception for domain. e.g.
User.metaClass.static.save = {
throw new IllegalStateException("Object is not in a state to be save.")
}
You could use hooks if not sure about meta-programming as below.
def beforeInsert() {
throw new IllegalStateException("Object is not in a state to be save.")
}
def beforeUpdate() {
throw new IllegalStateException("Object is not in a state to be updated.")
}
def beforeDelete() {
throw new IllegalStateException("Object is not in a state to be deleted.")
}
Haven't tried mapWith for inserts / updates as it actually don't allow creation of a table but everything like a domain is available.
static mapWith = "none"
Last but not least we could also use transactions but these won't be of that much help. Like in service you could use #Transactional(readOnly=true). But this will just help in services.
Also, you could disable versioning and want cache just only for reads.
static mapping = {
cache usage: 'read-only'
version false
}
I found this topic about read-only domain very helpful and worth.
I'm not sure about third bullet but you could try this as well.
Hope It would help!

Grails/Gorm: how to filter a list of domain objects without affecting the database

Say we have something like the standard Book domain object and bookCategory object. In my controller I want to return a subset of list of books to the view. That subset is not achievable using a find query. When I try to filer the return object, it deletes relationships from the database!
I tried this:
class BookCategory{
String name
static hasMany = [books:Book]
}
class Book{
String title
}
def myController() {
def categories
categories = BookCategory.list()
def user = getCurrentUser()
categories.each { category ->
category.books.removeAll { book ->
!isBookBannedForThisUser(book.title, user)
}
[bookCategories: categories]
}
}
The problem is that it permanently removes these books from the categories for all users from the database!!!
I tried putting the method in a service and using a readonly transaction, but this did not help.
I assume that even if I copy all the categories and books into new list, they will still update the DB as they will still have the book IDs (which I need)
Saving to the database when you dont say save() is very dangerous. is there a way to disable this feature completely?
There is a fundamental flaw in your approach. Do not modify your domain instances if you don't intend to have the changes persisted. Doing so is going to cause you headaches.
Your domain model is suppose to be your system of record. Any changes to it are suppose to be persisted.
If you need to gather up data and manipulate it without having it reflected in your domain model then use a DTO (data transfer object) or similar pattern.
Simply calling .discard() will discard the changes you have made from being persisted when the session automatically flushes.
Instead of working against the framework, and disabling behavior, change your approach to be correct.

Grails - the use of service layer

I have problems in organizing my code when I want to update a non-simple domain object. The problem is to separate responsibilities for the controller and the service layer.
More explicitly, assume that we have a domain class Client that depends on other domain classes like Address and so on.
In the view there is a gsp for editing some of the Clients properties including some of the nested properties like street on the Address.
When I would like to update those fields I call the update method on a Controller (in this case the ClientController).
I like the feature coming from the errors of a domain class when validated. Like if I in the Controller write
Client client = Client.get(params.id)
client.properties = params
client.validate()
If the client now has errors it is very easy to display them in the edit view.
But, I thought that updating, saving and getting the client from the database (Client.get(theId)) should be handled by the service layer. In my case I have to update or create other domain objects (like the Address) before I update the Client.
So one of my questions are how should the API look like for the service layer?
public ... updateClient(…)
In the literature they have the trivial example of updating the age of a person. So, their API consists of the id of the person and the new age. But, in my case I have about ten params from the view and they are just a subset of all properties of a client and I don't know which one of these that have changed.
I would like to have a Client in the controller that I can validate and resend to the edit view if it has validation errors.
I would like to handle the database interactions and transactions from the service layer.
How can I combine these? What responsibilities should the different layers have regarding update? How should the API of the service layer look like regarding update?
If there is a good reference implementation somewhere I would be happy to study it. Many times the service layer is unfortunately totally or partially ignored.
The missing piece of this puzzle is command objects. These classes represent the contract for your API into your services and provide you the ability to have a concrete class for your views and for validation. Let's look at an example.
Given a domain class of Client which as an Address and several Phone instances your Service layer might look like this:
...
class ClientService {
def updateClient(ClientUpdateCommand cmd) {
..
}
}
...
While the ClientUpdateCommand looks something like this:
#grails.validation.Validateable
class ClientUpdateCommand {
Long id
String name
List<PhoneUpdateCommand> phoneNumbers = []
AddressUpdateCommand address = new AddressUpdateCommand()
...
static constraints {
id(nullable: false)
name(nullable: false, blank: false, size:1..50)
...
}
...
}
You will note that this command object is composed of other command objects, and has constraints for validation. It may seem like you are replicating your domain classes here, but I have found that the more complex your application then more differences will appear between the domain classes and your command objects.
Next up is the use of the command object within your controller and your views. A controller method may look something like this:
Class ClientController {
...
def clientService
...
def edit(ClientUpdateCommand cmd) {
...
cmd = clientService.load(cmd.id)
Map model = [client: cmd]
render(view: 'edit', model: model)
}
def update(ClientUpdateCommand cmd) {
Map model = [client: cmd]
if (cmd.hasErrors() {
render(view: 'edit', model: model]
return
} else {
clientService.update(cmd)
...
}
...
}
}
I have left a lot out of the controller as I didn't want to bore you with the details but rather show how a command object replaces the domain instance. In some ways it's a little bit more work but it moves you completely away from manipulating the domain classes and delegates that to the service you have created. You will also notice that the command object replaces the domain class instance for your model for your views. I won't bother giving you any examples of the GSPs since they really don't change much when using command objects like this.
I'm sure there could be entire chapters of books written on the subject, but hopefully this gives you some insight and you can see that the answer to your question(s) is: Command objects.

Grails efficient hasMany-Relationship in View

I'm saving contacts (email, mobile phone, ICQ, AIM etc.) for people like this:
class Person {
static hasMany = {
contacts: Contact
}
}
class Contact {
String code
ContactType type
}
class ContactType {
String name
}
In my view, I've written some Templates for displaying each contact with a select-box for the contact-type and a textfield for the code, spiced up with some JavaScript for adding and deleting.
My question is: Is there an easy and elegant way to update the data similar to personInstance.properties = params or do I have to read out all the fields, deleting removed, updating changed and adding new ones?
I was looking into this some time ago but never got to refactor our code which handles parameters the old-fashioned way.
According to http://www.grails.org/Controllers+-+Data+Binding you can do something like this
def person = new Person(params['person'])
def contact = new Contact(params['contact'])
def conctactType = new ContactType(params['contactType'])
as long as request params are properly namespaced
person.contact.code
person.contact.type.name
You would still have to find out how to handle one to many. Maybe someone who knows can chip in.
Edit:
Came across this doc which describes how to handle one-to-many. It doesn't appear on the main grails site:
http://svn.codehaus.org/grails/tags/GRAILS_DOCS_1_1/src/guide/6.1.6%20Data%20Binding.gdoc

Resources