In Grails If I have a Command object such as
class MyCommand {
MyObject object;
}
If the incoming request data has an ID value for object then when the Grails data binding occurs my command object is actually populated with a instance of the object from the database.
I don't want this. I just want a new instance of MyObject populated with the incoming request data. I don't care of if there is already an instance in the DB with the same ID, I will handle that on my own.
How can disable this DB type data-binding at either a global level or preferably some way (annotation?) at the property level.
The only other alternative I can think of is when I send the request data I will have the ID values and object properties separate and join them later. I don't want to do that if it can be avoided.
You can have endpoints called differently using ROLES. For example:
def show(){
Person user = new Person()
if(isSuperuser() && params?.id){
user = Person.get(params.id.toLong())
}else{
user = Person.get(springSecurityService.principal.id)
}
...
}
This sets it up so only admin's can supply the ID otherwise it uses the principal to get the logged in user.
Related
In my Grails App, I have bootstrapped an object of a domain class as:
def user1 = new Users(userID: 1, name: "John Doe")
user1.save()
In my dashboard controller i have retrieved the object and modified its property name as:
Users userObj = Users.get((Long) 1)
println(userObj as JSON); // This gives me: {"class":"com.prabin.domains.Users","id":1,"name":"John Doe"}
userObj.name = "anonymous"
Now i create a new Users object to retrieve the changed object with same ID 1 as
Users otherUserObj = Users.get((Long) 1) // **Line 2** Is this retrieving from database or from GORM session?
print(otherUserObj as JSON)// This gives me: {"class":"com.prabin.domains.Users","id":1,"name":"anonymous"}
But the value of object in database is not changed. And even when i retrieve the Users object of same id 1 in another controller it gives me the initial object rather than the modified as:
Users userObjAtDifferentController = Users.get(1);
print(userObjAtDifferentController) //This gives me: {"class":"com.prabin.domains.Users","id":1,"name":"John Doe"}
My question is, if the value is not changed in the database, why it gives me the modified object at Line 2 though i have retrieved the object using GORM query (which i guess should retrieve from the database)?
I have also tried using save() after the modification but the result is same.
userObj.save() //doesn't show the changes in database.
My guess is that the object is not being saved to the database because some constraint(s) are invalid. You can determine whether this is the case by replacing your calls to save() with save(failOnError: true). If my guess is correct, an exception will be thrown if saving to the database fails.
When you call the save() method on a domain object, it may not persist in the database immediately. In order to persist the changed value to the database, you would need to do the following.
userObj.save(flush: true)
By using flush, you are telling GORM to persist immediately in the database.
In some cases when validation fails, the data will still not persist in the database. The save() method will fail silently. To catch validation errors as well as save to the database immediately, you would want to do the following
userObj.save(flush:true, failOnError:true)
If validation errors exist, then the GROM will throw ValidationException (http://docs.grails.org/latest/api/grails/validation/ValidationException.html)
You need to consider two things:
If you do save(), it only retains in hibernate session, until you flush it the changes does not persist in database. So, better do save(flush:true, failOnError: true) and put in try/catch block and print exception.
And another important things is, your method in controller needs to be with #Transactional annotation, without it your changes does not persist in database, you will encounter Connection is read-only. Queries leading to data modification are not allowed. exception.
Hope this helps, let me know if your issue is fixed. Happy coding . :)
For a project I'm currently working on I need to dynamically add properties to a domain class and persist them later in the database. In general, I need a key/value store attached to a "normal" domain class. Sadly I cannot use a NoSQL database (e.g. Redis).
My approach would be to handle the additional properties on a save() by identifying them within afterInsert or afterUpdate and writing them to another table - I would prefer not to use a map property within the domain class but an additional "Field" table (to better support searches).
I tried to add properties using the metaClass approach:
person.metaClass.middlename = "Biterius"
assert person.middlename == "Biterius" // OK
This works and I can identify the additional properties in the afterInsert/afterUpdate methods but it seems that I cannot change the value thereafter - i.e., the following does not work:
person.middlename = "Tiberius"
assert person.middlename == "Tiberius" // FAIL
Then I tried an Expando approach by extending the Person class by the Expando class (directly ("Person extends Expando") and via an abstract intermediate class ("Person extends AbstractPerson" and "AbstractPerson extends Expando")).
def person = new Person()
assert person in Person // OK
assert person in AbstractPerson // OK
assert person in Expando // OK
Both variants did not work - I could assign values to arbitrary "properties" but the values were not stored!
person.mynewproperty = "Tiberius" // no MissingPropertyException is thrown
println person.mynewproperty // returns null
So how can I add properties to a domain class programmatically during runtime, change them and retrieve them during afterInsert or afterUpdate in order to "manually" store them in a "Fields" table?
Or am I doing something completely wrong? Are there other / simpler ways to do this?
What about turning your DB into a "NoSQL" one?
In one of my projects, I just used a String-property to store a map as JSON-Object.
For Groovy it's not a big problem to convert between a map and a JSON-Object. And since you can access a map just like an object with properties, I found this solution very convenient.
Only drawback: you have to plan the size of your String-property in advance...
Update: sorry, just read that you want to support searches...
what about
class Person {
...
static hasMany = [extProperties:KeyValue]
...
def invokeMethod(String name, args) {
if (name.startsWith('get')) {
//an unknown properties's getter is called
}
//add same for setter
}
}
class KeyValue {
String key
String value
}
I guess such a schema would give you all freedom you need. Even without the hasMany, you can make use of invokeMethod to handle your external tables...
The getter and setter can save your values in a transient string propertie (static transients = ['myTransientProperty']). This property should be available in the afterInsert / `afterUpdate´ events.
Why don't you just create a map of strings on the domain object and store your extra data there manually? Unless you're storing complex data you should be able to cast anything you need to/from a string.
I am trying to overwrite getter and setter for domain class. The rational for doing is so that i don't have to redo initialization of this domain class that is in so many places in code.
I have a domain class 'Bank' that used to have one 'address' and it was initialized as follows:
new Bank(address: Address)
Now, i need multiple addresses, so I have a mapping class BankAddress and Bank now have 'addresses' list of BankAddress
To keep initialization the same 'new Bank(address:Address)', i am rewriting 'getAddress' and 'setAddress' like the following:
Address getAddress(){
if(addresses?.size()>0){
addresses.asList().get(0).getAddress()
}else{
return null
}
}
void setAddress(Address instance){
if(addresses?.size()>0){
addresses*.delete()
addresses.clear()
}
def bankAddress = new BankAddress(address: instance, bank: this, isPrimary: true).save(flush: true)
addToAddresses(bankAddress)
}
Problem is that while my setter is called, the 'instance' parameter of the function is empty making to fail on save - new Bank(address:someAddress):
'AddressId', table 'someDB.Config.BankAddress'; column does not allow nulls. INSERT fails.
How come the setter has empty argument? ... I am newbee to groovy & its dynamic nature
Thank You for your help
In your setter you're creating a new BankAddress object and then doing a save(flush:true). One of the properties of your BankAddress object is the submitted Address object. If the submitted Address object hasn't been saved to the database already, the new BankAddress object will try to save a null id in its foreign key column in the database, which will fail because the foreign key column is not nullable.
Make sure your submitted Address object has already been persisted to the database so it has a primary key id, or delay persisting the new BankAddress object until later.
Guys,
I have a following domain class:
class Product {
String name,
String productRecord,
static transients = ['productRecord']
}
productRecord is a field which is generated automatically based on the id of the Product instance.
So I've been thinking, is there a place which will be automatically called when a domain instance is load to generate the productRecord number?
What's the best way to do that?
You can probably leverage the built-in Domain Events:
GORM supports the registration of events as methods that get fired
when certain events occurs such as deletes, inserts and updates. The
following is a list of supported events:
beforeInsert - Executed before an object is initially persisted to
the database
beforeUpdate - Executed before an object is updated
beforeDelete - Executed before an object is deleted
beforeValidate - Executed before an object is validated
afterInsert - Executed after an object is persisted to the database
afterUpdate - Executed after an object has been updated
afterDelete - Executed after an object has been deleted
onLoad - Executed when an object is loaded from the database
Have a look at the docs for some examples.
Typically this is done by creating a read-only getter method and put the generation logic in there. For example:
class Product {
String name,
String getProductRecord{ "Record " + id },
static transients = ['productRecord']
}
Another example is available here.
I'm writing an app that we may be switching out the repository later (currently entity framework) to use either amazon or windows azure storage.
I have a service method that disables a user by the ID, all it does is set a property to true and set the DisabledDate. Should I call to the repository, get that user, set the properties in the service, then call to the save function in the repository? If I do this, then thats 2 database calls, should I worry about this? What if the user is updating the profile at the same time the admin is calling the disable method, and calls the user calls the save method in the repository (which currently holds false for the IsDisabled property?) Wouldn't that set the user back to being enabled if called right after the disabled method?
What is the best way to solve this problem? How do I update data in a high concurrent system?
CustomerRepository:
// Would be called from more specific method in Service Layer - e.g DisableUser
public void Update(Customer c)
{
var stub = new Customer { Id = c.Id }; // create "stub"
ctx.Customers.Attach(stub); // attach "stub" to graph
ctx.ApplyCurrentValues("Customers", c); // override scalar values of "stub"
ctx.SaveChanges(); // save changes - 1 call to DB. leave this out if you're using UoW
}
That should serve as a general-purpose "UPDATE" method in your repository. Should only be used when the entity exists.
That is just an example - in reality you should/could be using generics, checking for the existence of the entity in the graph before attaching, etc.
But that will get you on the right track.
As long as you know the id of the entity you want to save you should be able to do it by attaching the entity to the context first like so:
var c = new Customer();
c.Id = someId;
context.AttachTo("Customer", c)
c.PropertyToChange = "propertyValue";
context.SaveChanges();
Whether this approach is recommended or not, I'm not so sure as I'm not overly familiar with EF, but this will allow you to issue the update command without having to first load the entity.