1

I'm using grails 3.3.9 with a sql server db. I'm using default scaffold-ed code for my domain class. When I hit the index page, I get the No Session found for current thread error. For using the default scaffold-ed code, I'm a bit stumped as to why this is happening. In Grails 2.x once I scaffold the app just works. Anyway here is my code and hopefully someone can shed some light on what I don't obviously know:

application.yml

hibernate: cache: queries: false use_second_level_cache: false use_query_cache: false dataSource: pooled: true jmxExport: true driverClassName: org.h2.Driver username: sa password: '' environments: development: dataSource: dbCreate: create-drop url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE dataSources: tst: dbCreate: update url: jdbc:sqlserver://TESTSERVER;databaseName=Technician;useNTLMv2=true driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver dialect: org.hibernate.dialect.SQLServer2012Dialect pooled: true username: user password: 'pass' formatSql: true logSql: true test: dataSource: dbCreate: update url: jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE production: dataSource: dbCreate: none url: jdbc:h2:./prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE properties: jmxEnabled: true initialSize: 5 maxActive: 50 minIdle: 5 maxIdle: 25 maxWait: 10000 maxAge: 600000 timeBetweenEvictionRunsMillis: 5000 minEvictableIdleTimeMillis: 60000 validationQuery: SELECT 1 validationQueryTimeout: 3 validationInterval: 15000 testOnBorrow: true testWhileIdle: true testOnReturn: false jdbcInterceptors: ConnectionState defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED 

build.gradle

buildscript { repositories { mavenLocal() maven { url "https://repo.grails.org/grails/core" } } dependencies { classpath "org.grails:grails-gradle-plugin:$grailsVersion" classpath "org.grails.plugins:hibernate5:${gormVersion-".RELEASE"}" classpath "com.bertramlabs.plugins:asset-pipeline-gradle:2.15.1" } } version "0.1" group "tstsupport" apply plugin:"eclipse" apply plugin:"idea" apply plugin:"war" apply plugin:"org.grails.grails-web" apply plugin:"asset-pipeline" apply plugin:"org.grails.grails-gsp" repositories { mavenLocal() maven { url "https://repo.grails.org/grails/core" } } dependencies { compile "org.springframework.boot:spring-boot-starter-logging" compile "org.springframework.boot:spring-boot-autoconfigure" compile "org.grails:grails-core" compile "org.springframework.boot:spring-boot-starter-actuator" compile "org.springframework.boot:spring-boot-starter-tomcat" compile "org.grails:grails-web-boot" compile "org.grails:grails-logging" compile "org.grails:grails-plugin-rest" compile "org.grails:grails-plugin-databinding" compile "org.grails:grails-plugin-i18n" compile "org.grails:grails-plugin-services" compile "org.grails:grails-plugin-url-mappings" compile "org.grails:grails-plugin-interceptors" compile "org.grails.plugins:cache" compile "org.grails.plugins:async" compile "org.grails.plugins:scaffolding" compile "org.grails.plugins:events" compile "org.grails.plugins:hibernate5" compile "org.hibernate:hibernate-core:5.1.16.Final" compile "org.grails.plugins:gsp" console "org.grails:grails-console" profile "org.grails.profiles:web" runtime "org.glassfish.web:el-impl:2.1.2-b03" runtime "com.h2database:h2" runtime "org.apache.tomcat:tomcat-jdbc" runtime "com.bertramlabs.plugins:asset-pipeline-grails:2.15.1" runtime "com.microsoft.sqlserver:mssql-jdbc:7.2.1.jre8" testCompile "org.grails:grails-gorm-testing-support" testCompile "org.grails.plugins:geb" testCompile "org.grails:grails-web-testing-support" testRuntime "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1" testRuntime "net.sourceforge.htmlunit:htmlunit:2.18" } bootRun { jvmArgs('-Dspring.output.ansi.enabled=always') addResources = true String springProfilesActive = 'spring.profiles.active' systemProperty springProfilesActive, System.getProperty(springProfilesActive) } assets { minifyJs = true minifyCss = true } 

Domain class: TST_Customer.groovy

package TSTSupport class TST_Technician { String techCode String techName boolean tec990Flag boolean tecCCFlag Date tecCreateDate String tecCreatedBy Date tecModifyDate String tecModifiedBy boolean tecActiveFlag static constraints = { techCode shared: "techCode" techName blank: false, maxSize: 75 tecCreatedBy blank: false, maxSize: 35 tecModifyDate nullable: true tecModifiedBy blank: false, maxSize: 35 } static mapping = { datasource "tst" table name: "lkp_Technician", schema: "dbo", catalog: "Technician" version false id generator: 'assigned', name: 'techCode', type: 'string' techCode column: '[TechnicianCode]' techName column: '[TechnicianName]' tec990Flag column: '[Tech990Flag]' tecCCFlag column: '[TechCCFlag]' tecCreateDate column: '[TechCreateDate]' tecCreatedBy column: '[TechCreatedBy]' tecModifyDate column: '[TechModifyDate]' tecModifiedBy column: '[TechModifiedBy]' tecActiveFlag column: '[TechActiveFlag]' } } 

Controller

package TSTSupport import grails.validation.ValidationException import static org.springframework.http.HttpStatus.* class TST_CustomerController { TST_CustomerService TST_CustomerService static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"] def index(Integer max) { params.max = Math.min(max ?: 10, 100) respond TST_CustomerService.list(params), model:[TST_CustomerCount: TST_CustomerService.count()] } def show(Long id) { respond TST_CustomerService.get(id) } def create() { respond new TST_Customer(params) } def save(TST_Customer TST_Customer) { if (TST_Customer == null) { notFound() return } try { TST_CustomerService.save(TST_Customer) } catch (ValidationException e) { respond TST_Customer.errors, view:'create' return } request.withFormat { form multipartForm { flash.message = message(code: 'default.created.message', args: [message(code: 'TST_Customer.label', default: 'TST_Customer'), TST_Customer.id]) redirect TST_Customer } '*' { respond TST_Customer, [status: CREATED] } } } def edit(Long id) { respond TST_CustomerService.get(id) } def update(TST_Customer TST_Customer) { if (TST_Customer == null) { notFound() return } try { TST_CustomerService.save(TST_Customer) } catch (ValidationException e) { respond TST_Customer.errors, view:'edit' return } request.withFormat { form multipartForm { flash.message = message(code: 'default.updated.message', args: [message(code: 'TST_Customer.label', default: 'TST_Customer'), TST_Customer.id]) redirect TST_Customer } '*'{ respond TST_Customer, [status: OK] } } } def delete(Long id) { if (id == null) { notFound() return } TST_CustomerService.delete(id) request.withFormat { form multipartForm { flash.message = message(code: 'default.deleted.message', args: [message(code: 'TST_Customer.label', default: 'TST_Customer'), id]) redirect action:"index", method:"GET" } '*'{ render status: NO_CONTENT } } } protected void notFound() { request.withFormat { form multipartForm { flash.message = message(code: 'default.not.found.message', args: [message(code: 'TST_Customer.label', default: 'TST_Customer'), params.id]) redirect action: "index", method: "GET" } '*'{ render status: NOT_FOUND } } } } 

Service

package TSTSupport import grails.gorm.services.Service @Service(TST_Customer) interface TST_CustomerService { TST_Customer get(Serializable id) List<TST_Customer> list(Map args) Long count() void delete(Serializable id) TST_Customer save(TST_Customer TST_Customer) } 
6
  • I've seen this in an app I'm working on, and it seems if you send a domain class to a view, an in that view you try to access a field that represents a relationship you'll get this error. It work around it in my case I pilled out the relationship field in the controller, and s pass that in the map for the view. I'm not sure if there is another work around. Commented Mar 12, 2019 at 19:02
  • @virtualdogbert I have no relationships for this domain class. In fact, this is the only domain class in my app. There are also no Foreign Keys in this database table. Commented Mar 12, 2019 at 20:23
  • Well, it was worth a shot, I would post a link to your question on the Grails slack channel. grails.slack.com/messages/C07M0GTDE Commented Mar 12, 2019 at 22:55
  • @virtualdogbert Sorry but I'm not sure how to get an actual invite to the channel. I don't see where the admin's contact info is shown. Commented Mar 13, 2019 at 13:36
  • grails-slack.cfapps.io Commented Mar 14, 2019 at 14:02

1 Answer 1

1

I actually had to Google the answer (none of the suggestions given to me worked for me). Anyway, in the controller you prefix right above the classname

@Transactional("name of datasource")

Full example:

package TSTSupport import grails.validation.ValidationException import static org.springframework.http.HttpStatus.* @Transactional("tst") class TST_CustomerController { TST_CustomerService TST_CustomerService static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"] def index(Integer max) { params.max = Math.min(max ?: 10, 100) respond TST_CustomerService.list(params), model:[TST_CustomerCount: TST_CustomerService.count()] } def show(Long id) { respond TST_CustomerService.get(id) } def create() { respond new TST_Customer(params) } def save(TST_Customer TST_Customer) { if (TST_Customer == null) { notFound() return } try { TST_CustomerService.save(TST_Customer) } catch (ValidationException e) { respond TST_Customer.errors, view:'create' return } request.withFormat { form multipartForm { flash.message = message(code: 'default.created.message', args: [message(code: 'TST_Customer.label', default: 'TST_Customer'), TST_Customer.id]) redirect TST_Customer } '*' { respond TST_Customer, [status: CREATED] } } } def edit(Long id) { respond TST_CustomerService.get(id) } def update(TST_Customer TST_Customer) { if (TST_Customer == null) { notFound() return } try { TST_CustomerService.save(TST_Customer) } catch (ValidationException e) { respond TST_Customer.errors, view:'edit' return } request.withFormat { form multipartForm { flash.message = message(code: 'default.updated.message', args: [message(code: 'TST_Customer.label', default: 'TST_Customer'), TST_Customer.id]) redirect TST_Customer } '*'{ respond TST_Customer, [status: OK] } } } def delete(Long id) { if (id == null) { notFound() return } TST_CustomerService.delete(id) request.withFormat { form multipartForm { flash.message = message(code: 'default.deleted.message', args: [message(code: 'TST_Customer.label', default: 'TST_Customer'), id]) redirect action:"index", method:"GET" } '*'{ render status: NO_CONTENT } } } protected void notFound() { request.withFormat { form multipartForm { flash.message = message(code: 'default.not.found.message', args: [message(code: 'TST_Customer.label', default: 'TST_Customer'), params.id]) redirect action: "index", method: "GET" } '*'{ render status: NOT_FOUND } } } } 
Sign up to request clarification or add additional context in comments.

1 Comment

Amazing, this works for me in Grails 4+, thanx

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.