Unable to Invoke Post Operation When Using a DTO for Grails - grails

I would like to use a DTOs when I'm working with grails. My DTO basically looks like this:
class ProjectDTO {
Long id
Long version
String name
}
I've put the file in src/groovy so grails understands this isn't a domain model.
I also have a converter to transfrom my projectDTO into a project object.
#Transactional
def save(ProjectDTO projectInstance) {
if (projectInstance == null) {
render status: NOT_FOUND
return
}
ProjectDTOConverter converter = new ProjectDTOConverter()
Project p = converter.convertFromDTOForSave(projectInstance)
p = projectService.save(p)
List<ProjectDTO> r = converter.convertToDTO(p)
respond r, [status: CREATED]
}
This strategy seems to work fine for GET, POST, and DELETE operations, but not for PUT operations. It seems that for put operations, grails always considers my projectInstance variable to be null, even though it is passed in properly.
I did a SQL spool and it seems that when you pass in any object into a PUT operation, grails assumes you're working with a domain object, and issues a SQL statement to try retrieve the object from the database. If the object can't be retrieved, the projectInstance is nulled out for some reason.
Does anyone know if there is a way to instruct Grails that the object i'm passing in for a PUT operation is not a domain model, and grails shouldn't retrieve it from the database?

Related

Domain not persisted even after explicit save() when using read() to get it

I retrieved the domain object using read(), changed some properties on it and explicitly saved it using save(). I can see version being updated but not properties
Properties should be updated along with the version as mentioned in grails read() documentation
Example Domain:
class AdhocChargeType{
String adHocChargeType
String glCode
}
Controller test method:
class AdhocChargeTypeController
{
def testRead(Long id)
{
AdhocChargeType adHocChargeType = AdhocChargeType.read(id)
adHocChargeType.properties = [adHocChargeType:"changed?"]
adHocChargeType.save()
}
}
Grails save() method silently fails. If you have validation errors, then it will not save.
try with
save flush:true, failOnError:true
Resolve if there is any validation errors. The data should persist after that.
Upon saving a domain instance, Grails validates it using the defined constraints. The save will fail, if values in the domain instance violate those constraints. The problem is, this failure occurs quietly: you only know about it if you check the return value of save() or call hasErrors().
if (!adHocChargeType.save()) {
// Save failed! Present the errors to the user.
...
}
Another approach is :
adHocChargeType.save(failOnError: true)
I suggest have a look into GORM best practices:
http://spring.io/blog/2010/06/23/gorm-gotchas-part-1/
http://spring.io/blog/2010/07/02/gorm-gotchas-part-2/
http://spring.io/blog/2010/07/28/gorm-gotchas-part-3/

Grails3 generate-all generates faulty create action code

When I use generate-all package.DomainObject, it generates a controller where create action is generated as:
def create() {
respond new DomainObject(params)
}
When I call the localhost:8080/DomainObject/create even without making any code change, it throws an exception:
groovy.lang.MissingPropertyException: No such property: controller for
class: package.DomainObject
It looks like introspection is failing for properties that params map has and DomainObject does not have. This is surprising because in the grails 2, introspection used to just ignore the non-matching properties and it also used to do necessary type conversions on fields as well (now if DomainObject has an int property, it will throw a type mismatch exception because params map passes it as String). This is really inconvenient. Did something change or I am missing something?
Using the map constructor and setting properties in bulk with a map in Grails is basically the same as in Groovy, but it has logic to exclude 'controller', 'action', and 'format' keys to keep controller code like this uncluttered. That broke in 3.x and has been reported in the issue tracker. It's not marked fixed but works correctly for me in a simple 3.0.4 test app.
As a temporary workaround you can copy the params map and remove values stored under those keys and use the 'fixed' map for the constructor:
def create() {
def fixedParams = ([:] + params) // copy
['controller', 'format', 'action'].each { fixedParams.remove it }
respond new Thing(fixedParams)
}

Grails pure sql and domain class

I have an existing MySQL database and in grails controller i want use pure SQL query instead of GORM (it's too difficult to run the reverse engineering plugin).
I want return json object
So my idea is, in the controller, to execute a sql query and map the result to an object and render that object in json (i have see the grails REST tutorial anyway).
To map the sql query result to an object, can i use the grails domain class or i must create a pure groovy object?
Can i use the command:
grails create-domain-class
or i must create a DTO groovy object (in src/groovy folder)?
You don't need to create a DTO to solve your problem you just need to use an HQL, like this:
def result = Domain.executeQuery("FROM DOMAIN WHERE conditions");
render result as JSON;
I hope this solve your problem.
If you want to pass the native sql then you can also use spring jdbcTemplate.
Configuration:
import org.springframework.jdbc.core.JdbcTemplate
beans = {
..........
jdbcTemplate(JdbcTemplate) {
dataSource = ref('dataSource')
}
}
Controller:
def jdbcTemplate
List actionMethod(){
String query = "your pure native query example select ........from table"
List results = jdbcTemplate.queryForList(queryStr)
return results as JSON
])
}
Create DTO object and map the required columns one by one .I used the DTO approach since my number of columns to be mapped were quite less.
If your result is simple enough, you can use groovy.sql.Sql class and do the querying directly in the controller:
def results = []
Sql db = new Sql( dataSource )
db.eachRow( "select avg( rating ) as rating, main_profile_id as id from profile" ) {
results << [ it.id, it.rating ]
}
db.close()

Web API OData Actions with Entity as parameter

I have a requirement to encapsulate pieces of business logic within a transaction in an OData Web API service. Some of these pieces will need to accept one or more entities.
An example use case might be StockProduct and this might accept a Product entity and a Location entity. It would create the product and update stock records for the Location.
The approach I've taken is to create an unbound OData action that accepts these entities so that both of these can be operated on in a single transaction. Unfortunately neither can Entities be used as an ODataActionParameter nor can they be part of a class and used as a complex parameter.
I can think of a two ways around this:
Create a DTO class that is not an entity that is a mirror of each of my mirror classes and convert from DTO to Model within my action. The problem here is that I already have a DTO for each Model eg. Product.cs and ProductDTO.cs and don't really want to have to create a third class. (Currently, the ProductDTO.cs is used for Posts, Puts, Patches and Deletes and the Product.cs is used for Gets).
Abandon OData actions and create a simple end point that accepts whatever I like. I'm not keen on going down the second route as I'd like to use OData exclusively.
Any thoughts or suggestions?
You can use the ActionConfiguration.EntityParameter() method to bind an entity as a parameter to your OData action method.
Here is an example:
ActionConfiguration validate = ModelBuilder.EntityType<TEntity>()
.Collection.Action("Validate");
validate.Namespace = "Importation";
validate.EntityParameter<TEntity>(typeof(TEntity).Name);
validate.CollectionParameter<string>("UniqueFields");
validate.Returns<ValidationResult>();
However, note that the ModelState will not check against the content of the supplied Entity and will set any missing properties to null and properties exceeding the StringLength(x) annotation in your model will still pass. If you wish to validate the entity itself after, use this bit of code in your action method:
[HttpPost]
public virtual IHttpActionResult Validate(ODataActionParameters parameters)
{
//First we check if the parameters are correct for the entire action method
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
else
{
//Then we cast our entity parameter in our entity object and validate
//it through the controller's Validate<TEntity> method
TEntity Entity = (TEntity)parameters[typeof(TEntity).Name];
Validate(Entity, typeof(TEntity).Name);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IEnumerable<string> uniqueFields = parameters["UniqueFields"] as IEnumerable<string>;
bool result = Importer.Validate(Entity, uniqueFields);
return Ok(result);
}
}
As for your StockProductDTO, it seems to me that this is an new Business Entity by itself and should be treated as such.
You can use a batch request to perform multiple operations within a single request. This allows you to use your existing controllers for inserting your two objects.
https://aspnetwebstack.codeplex.com/wikipage?title=Web+API+Request+Batching

Grails Session scope for service not working as expected

I'm making a web app that stores reports of various types as domain objects, so I have a domain object HeadOfHousehold which contains name data, and references to other domain objects such as the reports, addresses, and any dependants. I am trying to build a list of recently viewed/created HeadOfHousehold objects. After multiple Google searches, and scouring the manual, it appeared that a service would be an appropriate solution. So I created ClientListService:
#Transactional
class ClientListService {
static scope = "session"
String message // right now I'll be happy to just see the same message across
// pages I can add a list and manipulate it later.
}
I thought I could then reference it in my various controllers, and it would persist Something like this:
def clientListService
def index(){
hasSearched = false
clientListService = new ClientListService(message: "Hello")
[errorMessage: params.errorMessage, clients:clientListService]
}
Which should be available in a later controller:
class HeadOfHouseHoldController {
def clientListService
def index() {
[customer: HeadOfHousehold.get(params.id), clients: clientListService]
}//...
However when I try to get the message, it appears as if the object is null.
From my index.gsp:
***************${clients?.message}********************
So I don't know if I am not defining session properly (I'm not doing anything special to do so), if I'm misunderstanding how the session scope works, or something else. I do see the proper message on the original page which has defined the object, however I don't see it on any subsequent pages.
Also, I'm not sure if this is the proper way to go about this; right now all I really need is the list of HeadOfHouseholds that I would need (so I can add to the list from other pages), however I can see possibly adding other logic and items into such a class.
I think you understood the session scope correctly. Each Spring bean with a session scope is bound to the HTTP session.
But your first controller listing does it all wrong. You are not supposed to instantiate the service class yourself. This is what Spring (Grails) does.
class FooController {
def clientListService // gets autowired by Grails/Spring
def index(){
hasSearched = false
clientListService.message = 'Hello' // only assign a String value to the service
[errorMessage: params.errorMessage, clients:clientListService]
}
}
This means you cannot not do something like
clientListService = new ClientListService(message: "Hello")
and expect your code to work. Hope this helps.

Resources