Grails application design - grails

In Grails application i have EmploymentSeeker domain as below :
class EmploymentSeeker {
String fullName
String expYears
Boolean haveDrivingLic
String gender
String eduQualification
String courses
String currentTitle
int age
}
I want to make the user in the create view to add previous references. user may add up to 4 references , but I don't know how to do it - shall I create Emp references domain and link it to employment seeker domain static belongsTo?

Related

grails v3.2.6 /gorm embedded class in same domain class.groovy creates dummy DB table

in the grails/gorms docs it says you can put the embedded class in the same domain class file as the top level parent domain class - this works from code perspective but it still generates a GeoAddress table, as well as embedding the columns into the source Venue table. test data is input in venue - geoAddress table stays empty.
documentation implies this embedded table shouldnt be generated. I can try and move the GeoAddress into its own src/groovy file, so its out of the grails-app/domain folder, but then i have to 'remember i have done this'. it would be much 'cleaner' to keep in same file as the containing class.
other than promoting the GeoAddress back to full domain class in its own right - how can i tell gorm not to generate the table for it when its use is embedded ?
my venue.groovy in grails-app/domain folder
class Venue {
String name
LocalDate dateCreated
LocalDate lastVisited
LocalDate lastUpdated
GeoAddress location
Collection posts
static hasMany = [posts:Post]
static embedded =['location']
static constraints = {
lastVisited nullable:true
location nullable:true, unique:true
posts nullable:true
}
static mapping = {
location cascade: "all-delete-orphan", lazy:false, unique:true
posts sorted: "desc", cascade:"save-update"
}
}
class GeoAddress {
String addressLine1
String addressLine2
String addressLine3
String town
String county
String country = "UK"
String postcode
//adds addTo/removeFrom methods to venue
static belongsTo = Venue
static constraints = {
addressLine1 nullable:true
addressLine2 nullable:true
addressLine3 nullable:true
town nullable:true
county nullable:true
country nullable:true
postcode nullable:true
}
}
ok - i did find a way to use the geoLocation as embedded and stop it creating a table .
I had to setup GeoLoction as static inner class in side venue. When you do that and run the app you dont get the extra spurious domain table in in the DB. It has to be static inner class as the GeoLocation has a static declaration for constraints.
I'm not sure if this is a bug or what - but the grails documentation is incorrect in the suggestion in section 5.2 - composition in gorm, which says
If you define the Address class in a separate Groovy file in the
grails-app/domain directory you will also get an address table. If you
don’t want this to happen use Groovy’s ability to define multiple
classes per file and include the Address class below the Person class
in the grails-app/domain/Person.groovy file
modified class shown below. when you want to create one of these the format (for bootstrap/tests ) would look like new Venue.GeoLocation (...)
class Venue implements Serializable {
String name
LocalDate dateCreated
LocalDate lastVisited
LocalDate lastUpdated
GeoAddress location
Collection posts
//static hasOne = [location:GeoAddress] //, temp:TempLocation
static hasMany = [posts:Post] //but doesn't really own thats with user
static embedded =['location']
static constraints = {
lastVisited nullable:true
location nullable:true, unique:true
posts nullable:true
}
static mapping = {
location cascade: "all-delete-orphan", lazy:false, unique:true //eager fetch strategy
posts sorted: "desc", cascade:"save-update"
//comment out for now
//posts joinTable: [name:"venue_posts", key:"venue_id", column:"posts", type:Post]
}
static class GeoAddress {
String addressLine1
String addressLine2
String addressLine3
String town
String county
String country = "UK"
String postcode
//adds addTo/removeFrom methods to venue
static belongsTo = Venue
static constraints = {
addressLine1 nullable:true
addressLine2 nullable:true
addressLine3 nullable:true
town nullable:true
county nullable:true
country nullable:true
postcode nullable:true,
matches: /^([gG][iI][rR] {0,}0[aA]{2})|([a-pr-uwyzA-PR-UWYZ](([0-9](([0-9]|[a-hjkstuwA-HJKSTUW])?)?)|([a-hk-yA-HK-Y][0-9]([0-9]|[abehmnprvwxyABEHMNPRVWXY])?)) ?[0-9][abd-hjlnp-uw-zABD-HJLNP-UW-Z]{2})$/
}
}
}
Grails table generation base on Class name, try put embedded as Collection rather than Class.
I appear to have put postings on what is essentially same problem - careless. See also Can't get cascade save nor delete on embedded class ref to work
However to reprise: having the embedded class sitting below the main class in the grails-app/domain folders does not stop the embedded class from being generated (as it implies in the docs).
So Gorm goes ahead and creates you a Venue and a GeoLocation (my example here). However the usage is not what I expected either, which is why the test failed.
If you add the new GeoLocation as constructor arg to the venue, the transient instance is saved in the venue table in the embedded location columns in same table. If you delete the venue the entire row is deleted from venue table.
However, if you create a GeoLoaction first and save() it - it's actually stored in the GeoLocation table instead. Then adding it to the venue updates the columns the venue tables.
So when the test does a GeoLocation.list()/get(), it finds the row in that table rather than looking in the venue embedded columns.
I can't find a nice way out of this. The only way to stop geoLocation going into the DB is to move the the definition out of domain folders and put into src/groovy. But then your domain model is split across two subtrees, and getting the gorm validations to fire outside of the domains folder is more fiddly to achieve.
I think I have just had to accept using GeoLocation as full domain class rather than use embedded - and accept the join cost. At least that way the model/tests work as you might expect.
The outcome is: I am not sure embedded was a wise modelling decision and I'd recommend not using unless you really have to.

Unique key parts not showing in Create Form Grails

I have following Domain Class -
class xyz {
String name
String version
String vclass
Date dateCreated
static constraints = {
version(blank:false)
name (unique: ['version'])
}
static hasMany = [ yz: Yz ]
}"
when i create a record for it, i don't see an option to enter version, only name and vclass. Why?
In Grails, version is a special property of Domain classes used for optimistic locking. Rename your property to something other than version. You can read more about this in the user guide.

Grails Inventory Desgin

I have these domain class:
class Product {
Manufacture manufacture
Model model
Category category
int price
String productCondition
String productDescription
}
class Manufacture {
String manufactureName
static hasMany = [products:Product, models:Model]
}
class Model {
Manufacture manufacture
String modelName
static hasMany = [products:Product]
}
class Category {
String categoryName
static hasMany = [products:Product];
}
I am wondering if I need a Manufacture class, Model class, and Category class or if I can just use a String manufacture, etc.. Is there any advantage to having those additional domain classes than just having String manufacture, etc when it comes to searching? Say I want all products that are manufactured by Ford, or all products that are category car. I am confused on when I should make a domain class vs just using a field.
Thanks
The choice between one solution or the other one depends on how you plan to query the application and adapt it to future changes.
You could use only a Product domain class and with the appropriate database indexes on manufacture, model and category String fields the queries would go fast. But with this approach you can not evolve easily your domain to add new fields to manufacture, model and category.
I always prefer the domain class solution because I don't know how the application is going to evolve.
And intermediate solution can be use embedded domain classes.

Grails domain List field not being persisted

I have a domain class
class Something {
String name
String email
List<String> friends = []
}
In the domain class itself I have a method for Something objects which populates the friends list. But for some reason I am not able to persist this list. and it gets made null on browsing away from the gsp relevant to the domain modifying action.
Any suggestions as to why this is happening?
I think you instead need to write your domain as:
class Something {
String name
String email
List friends
static hasMany = [ friends: String ]
}

Inheritance for domain class in Grails or a flag would do?

I am making a website where Doctors and Patient both can login.
class Doctors {
String firstName
String lastName
String email
String password
String hospitalName
String NPINumber
}
And patients
class Patients{
String firstName
String lastName
String email
String password
}
As it is evident that there are lot of overlapping fields which are only used for authetication/login purpose, I was wondering if inheritance is a good idea or should I just create a flag in a single class.
So two options are:
OPTION-1
class Users{
String firstName
String lastName
String email
String password
}
class Doctors extends Users {
String hospitalName
String NPINumber
}
class Patients extends Users{
}
OPTION-2
class Users{
String firstName
String lastName
String email
String password
boolean isDoctor
String NPINumber
String hospitalName
}
I am not sure which of these designs I should choose so that it is extendable in future!
Option 1 is more OO for sure. However, I would still make a little bit of a change in order to make the design even better. Instead of extending User, why not have a User property which contains some of the common attributes. Extending the User class could make your design more complex. Maybe this topic can help you.
Also, as a suggestion, don't use the classes' names in the plural form. Imagine it's an entity for itself and not a collection of entities. Clearly your class Doctor, for example, represents one doctor specifically. Not more than one. So you should use Doctor, Patient and User.
Hope it helps.

Resources