简体   繁体   中英

How to call a service method inside of the domain in grails?

I have to call one method of my controller from my domain. I'm trying to find some answer but I don't find anything and I'm not sure if is possible. Sorry, if my question is wrong, but in the requeriments that I have I have to find a solution for this, because I have do it inside of the method beforeInsert() in my domain.

This is the error when I try to run the project:

| Error 2015-12-02 10:59:29,210 [localhost-startStop-1] ERROR hibernate.AssertionFailure - an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session) Message: null id in com.xxxx entry (don't flush the Session after an exception occurs)

Controller method:

def calculate(Integer max){
        params.max = Math.min(max ?: 10, 100)
        def users= User.findAllByType(null)
        LicenceTypeService.calculate(users) //This call a service
        redirect(action: "list", params: params)
    }

In my Domain:

protected void callCalculateWhencreateUser(){
        def users= User.find("from User order by id desc")
        LicenceTypeService.calculate(users) //This call a service
    }

def beforeInsert() {
        encodePassword()
        callCalculateWhencreateUser()
    }

In my Service:

def calculate(def users){

        //logic code

    }

The subject of your question is misleading: you say that you need to call a controller method from a domain, but what your code says is that you're trying to call a service method from both domain and controller.

You can't call a controller method from a domain, is conceptually wrong, but also you need a request to call a controller and you don't have it in a domain.

However, what you're trying to do is in fact the way to do it: leave the logic to the service and call it from controller and domain. But you're doing it wrong.

In the controller you need to declare the service, so spring will inject it into your controller, just like this:

class MyController {
    def licenceTypeService

    def calculate(Integer max){
        params.max = Math.min(max ?: 10, 100)
        def users = User.findAllByType(null)
        licenceTypeService.calculate( users )
        redirect(action: "list", params: params)
    }
}

You can use the actual type in the declaration of the service property instead of def, but the important thing is that the property name is the "logical name" of the service: the class name but with the first letter in lower case. That way the property will get injected by spring.

You should change the variable "user" for "users", it makes you think that is a single user but the finder you use returns a list of users instead.

On the domain you have to do just a bit more of work. You need to inject the service in the same way, but you need to add it to the "transients" list, so GORM will not try to create a field in the database for it or retrieve it from the database.

Like this:

class MyDomain {

    def licenceTypeService

    static transients = [ "licenseTypeService" ]

    def beforeInsert() {
        encodePassword()
        licenceTypeService.calculate( this )
    }
}

And your service would be something like:

class LicenceTypeService {

    def calculate( User user ) {
        // perform some calculation
        // do not call user.save() since this will be invoked from beforeInsert
    }

    def calculate( List<User> users ) {
        // If this is performed on several users it should be 
        // done asynchronously
        users.each {
            calculate( it )
            it.save()
        }
    }
}

Hope that helps.

However, depending on what you do in the calculate method (for a single user) it can be a method of the User class (that's a more OO solution).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM