2
votes

In my app I have a set of 1000 or so "HouseProto" domain objects, which have a bunch of static properties that I need in my "HouseInstance" object.

At scale, maybe there are large numbers of HouseInstance objects each modeled on the HouseProtos. Here is how I tried to model the HouseInstance domain object.

class HouseInstance {
    @Delegate
    HouseProto houseProto
    User agent
    static belongsTo=[world: World]
    static constraints = {
        agent nullable:true
    }
}

HouseProto has a lot of fields like "squareFeet" and "bedroomCount" etc. I used the @Delegate annotation because I'd like to be able to do something like

houseInstance.streetAddress

instead of

houseInstance.houseProto.streetAddress

but this fails on compile. Buried at the end of the console output below is a reference to the "features" field of HouseProto (a hasMany Set) which suggests that might have something to do with it. Remove the delegate annotation, though and it all works fine. (Feature is a domain class that belongsTo HouseProto.)

My question is simply whether or not the @Delegate annotation is incompatible with Domain classes because it interferes with GORM for some reason? It seems like it will do what I want if it can be made to compile.

HouseProto looks more or less like this:

class HouseProto {
    def houseService

    String streetAddress
    Owner owner
    Integer sqft
    Double acreage
    Integer bedroom
     ...
    Double kitchenQuality =0
    Double loanBalance =0
    Neighborhood neighborhood

    String toString() {
        "$streetAddress"
    }
    static hasMany = [features: Feature]
    static constraints = {
        streetAddress nullable: false, unique: true;
        owner nullable: true
        sqft nullable: false
        neighborhood nullable: false

    } 
  }

The runtime console output starts with this:

ERROR org.springframework.boot.context.embedded.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.BeanCreationException. Message: Error creating bean with name 'grailsCacheFilter': Cannot create inner bean '(inner bean)#5ec1152d' of type [grails.plugin.cache.web.filter.simple.MemoryPageFragmentCachingFilter] while setting bean property 'filter'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '(inner bean)#5ec1152d': Unsatisfied dependency expressed through method 'setUrlMappingsHandlerMapping' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'urlMappingsHandlerMapping': Unsatisfied dependency expressed through method 'setWebRequestInterceptors' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'openSessionInViewInterceptor': Cannot resolve reference to bean 'hibernateDatastore' while setting bean property 'hibernateDatastore'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hibernateDatastore': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.grails.orm.hibernate.HibernateDatastore]: Constructor threw exception; nested exception is org.hibernate.MappingException: collection element mapping has wrong number of columns: com.grapevine.negotiator2.HouseInstance.features type: object

Disconnected from the target VM, address: '127.0.0.1:57570', transport: 'socket'

ERROR org.springframework.boot.SpringApplication - Application      startup failed
1
Wild stab in the dark: have you tried to set all the attributes from HouseProto to be transients in the HouseInstance? If that works, you might as well be better off to just generate getters in HouseInstance on your own and mark them transient. Or on the next change to HouseProto you will see another cryptic error. I don't like "IDE generated" code like this at all, but this case might justify it, because the implicit DB-Model generation will be more transparent to the developer with it.cfrick
I thought about that, but seems maybe more work than just using house instance.proto. I was also thinking about implementing with missingMethod, so you could do houseInstance.squareFeet() which could return to houseInstnce.proto.squarefeet. Less typing, but I wonder if its very inefficient or not.GGizmos

1 Answers

1
votes

As far as I aware @Delegate is not supported in domains, you may have more luck using a trait that both HouseInstance and HouseProto implement