Can Grails 3.3 fields plugin f:display show many-to-many - grails

I'm working with Grails 3.3.9 but I can change that as necessary.
I would like to let the Grails fields plugin manage my CRUD as generated, or at least with minimal manual changes. The problem I have not been able to solve is when I have a many-to-many relationship and want to show the related instances from either side.
A simple example: two domain classes, Company and Worker. Each have a String name and each have a hasMany:
static hasMany = [companies: Company] // in Worker
static hasMany = [workers: Worker] // in Company
I don't identify that either class belongsTo the other.
When I generate-all and run the app, then use Worker / new CRUD to create new instances of Worker, all seems fine.
Then, when I create a company using Company / new CRUD, I am offered a drop-down of the already defined workers, which looks good; so I shift-click on a couple to include them in the new company definition. But then after the save, the show CRUD does not show a list of selected workers for the Company instance I just created. There is a field label "Workers" but no value shown next to it.
I can't seem to find any obvious way to encourage f:display to show that list - or maybe somehow the multi-select didn't produce the desired results.

Yes it can. Solved my problem. This page:
https://github.com/grails-fields-plugin/grails-fields/blob/master/grails-app/views/templates/_fields/_list.gsp
shows what the template is (should be?) to render fields. Wondering if that was somehow different than what's in my version, I installed that file in
...grails-app/views/templates/_fields/_list.gsp
and suddenly my many-to-many relations were visible.
Extra info that may be useful for others stumbling over this:
I followed the GORM reference manual recommendation for creating a many-to-many relationship where each side includes a
static hasMany = [...]
and the "owned" side also has a
static belongsTo =
I think I may have been confused as to the meaning of the belongsTo in this case - what it means is well explained here:
http://docs.grails.org/3.0.4/guide/GORM.html#manyToMany

Related

rename domain class, groovy and grails reverse engineering

How do a rename a domain class while reverse engineering or after reverse engineering.
i generated class using reverse engineering in Groovy and Grails.
the domain class name was AgentTable. I want to rename it as Agent. When i renamed the domain class using IntelliJ (right click - refactor - rename), it renamed the AgentTable to Agent whereever it was used. but when i start the server (run the app), giving error
"nested exception is org.hibernate.HibernateException: Missing table: agent"
I have to do this for few domain class. is it anyway i can give an alternative name while reverse engineering the domain classes.
or after domain class was created how do i rename it without this error.
Look into your database the name of the table it created for the agent. Once you know the name of the table add the following in your new domain
static mapping = {
table "table-name-here"
}
While it works I would not recommend #elixir 's approach.
In my opinion the mapping is not supposed to be used for renames. This is also how I understand the official documentation.
In the example they use it to map Person onto the 'people' table, not because of a rename but because of a semantic reason. Tables are typically named after the plural form. Here is a nice answer on another question regarding this. In the project I am working on the domain object 'User' is mapped to the table 'users'. You can not use the table name 'user' as it is an SQL statement.
Assumptions and clarifications:
In my experience Grails maps the domain name to the table name after these rules (example domain name 'MyExampleDomain':
separate the domain name by capital letters (My Example Domain)
lower case all (my example domain)
replace spaces with underlines (my_example_domain)
Following this your Domain Class 'AgentTable' has a table 'agent_table' in your respective database. After your rename Grails even tells you what it wants:
nested exception is org.hibernate.HibernateException: Missing table: agent
It wants to look up values in a table called 'agent' but it can not find it. The refactor function of IntelliJ does not rename the functions, so it will miss out on the database.
Luckily we know exactly what values it wants - the values previously found in 'agent_table'.
So why create this confusion with remapping domains and table names when we could just rename the table and be done with it?
The solution:
Execute an SQL script like this on your database:
ALTER TABLE <old_domain_name> RENAME TO <new_domain_name>;
The names are of course in their "table-form".
This simply renames your table to match the expected format in Grails. When restarting everything should be fine.
However you do not need to use rename. You could also create a whole new table, build it the way the domain objects wants it to be and then migrate the data. See section 'Problems with this approach' for information on when to use what.
Problems with this approach:
As always, tinkering with information a program depends on (and even generated itself) will often have some dire consequences if you aren't careful.
For example we have to pay attention to keys. If your domain object has a relation to other objects it will hold them in the table via foreign keys. Depending on how you chose to migrate the information in the table you might have deleted these foreign keys connections. You will have to add them via a separate SQL statement. When you choose to recreate the table this will happen for sure. Renaming it should keep the keys.
Another one are column names. If you choose to rename attributes you will also have to rename the columns via SQL. You will also have to remember the foreign keys other tables might have on the table you are renaming. RENAME did this automatically for me, but you should double check.
Why you should still stick with this approach:
Remapping domain objects to the tables with old names is bound to create code smell and confusion. Do you really want to remember these mappings in your head? And more importantly: do you really expect other people to have to work with this?
The best case is if people can't even tell if this object has ever had a different name and changing the database is the best way I know to achieve this.

What is the correct Grails ORM (GORM) implementation to use?

As a result of a change request I need to implement the correct ORM for my Grails application.
I currently have the following simple models and associations:
Agent
static hasMany = [fees:Fee]
Fee
static belongsTo = [agent:Agent]
However, now I need to implement the ability for a single Fee to be split amongst Agents. I ended up with the following:
Potential new models associations
Fee
static hasMany = [agentfees:AgentFee]
Agent
no associations ??
AgentFee
static belongsTo = [fee:Fee]
In my mind an AgentFee would contain:
a reference to a Fee
a reference to an Agent
the Agent's % split of the fee (e.g. 80%)
So my question is. Should I also have an association between Agents and AgentFees i.e. something like:
Fee
static hasMany = [agentfees:AgentFee]
Agent
static hasMany = [agentfees:AgentFee]
AgentFee
static belongsTo = [fee:Fee]
static belongsTo = [agent:Agent]
But this just feels wrong with the multiple belongsTo in AgentFee. What is the best way to implement the notion of "Fee Splits" using GORM?
Thanks in advance,
John
It sounds like you are changing the relationship to a many-to-many. Here is the documentation for that: http://grails.github.io/grails-doc/latest/guide/GORM.html#manyToMany
A many-to-many relationship needs a joining table at the DB level. However, you most likely don't need a domain for your joining table i.e. you don't need AgentFee. GORM will know to use a joining table.
The only time you need a domain object for your joining table is if the joining table has additional columns beyond the ones needed to facilitate the many-to-many relationship. In this case you would create a domain for the joining table and then create two one-to-many relationships, one in each direction.
answering questions from comments:
#Michael #John if you look at the underlying database tables then you'll see only a foreign key from one table to another, tables do not cross reference unless it's one-to-one, so simplifying the domain classes like I described earlier changes nothing in physical data and it's easier to maintain in your code (you don't have to use addTo() and removeFrom methods), you just create a dependent object and set it's reference to current (you always change only one thing)
Agent a = new Agent()
Fee fee = new Fee(
also, if you want to retrieve all related objects, you can create a property returning list like
class Fee {
Agent agent
}
class Agent {
List<Fee> getFees() {
Fee.findAllByAgent(this)
}
}
and use it like
Agent a = new Agent()
List<Fee> aAgentsFees = a.fees
of course it's read only, and if you want to create them:
Agent agent1 = new Agent()
Fee feeA = new Fee(agent: agent1)
Fee feeB = new Fee()
feeB.agent = agent1

Strange activity from many to many in grails

Hi I am getting some strange activity from a many to many in grails.
It seems to be calling its self recursively.
my domains are set up like:
Product domain:
class Product {
String name
String comments
static hasMany = [components:Components]
}
Component domain:
class Components {
Product product
static hasMany = [alternatives:Product]
static belongsTo = Product
}
This seems to be causing a infinate loop and not saving the components correctly.
I know when using JSON.use("deep") on a Product I get a ../.. in components. The next strange thing is that. If I as for a product as JSON after I saved that product everything works fine, but when I try and get the same product as JSON later I get the ../.. in components.
I am totally lost about this.
If you require more details please let me know and I will me best to comply.
If you're going to have a many-to-many relationship you need to store the relationship data somewhere. If your relationship was one-to-many you could store them in the client table (like how you already have a component having one specific product in your component table) but in many to many you need the relationship to be its own table. To do this in Grails, use the JoinTable attribute or create a separate domain class to handle the relationship. Probably the fact that you have one-to-many relationship with Product already for Components and the many-to-many relationship with no join table is why you are getting the weird recursion issue.

Custom Join table in grails

I have a following domains
User (in database called usermanagement) and
Account (in another database xyz)
Its an old system so i cannot really change the architecture of the system. I have been assigned task to implement a system that a certain users can only access certain accounts. This is a classic case of many-to-many relationship but the problem lies in the fact that these two domains are in two different databases. I googled if that was possible but i realized that it was not possible. So I now am thinking of creating a custom join table to store info on which user are allowed access to which accounts. The table can have two columns 'accountId' and 'userId'. So for this, do i have to create a new domain in grails or is there any cleaver way of doing this ?
Thanks in advance.
If you create joinTable in which DB you are going to create it and how you are going handle updates in main (Account,User) tables and ceep your join table up2date ?
I think (for this case) you don't need join table, you need handle business logic in application level.
You cane have 2 Domain classes each one pointed to different dataSource(DataBase).
http://grails.org/doc/latest/guide/conf.html#multipleDatasources
As I searched for solution of this, I did not find any sustainable solutions. I eventually narrowed down the probable solutions to two:
1. Create a domain table (only) using sql, some sort of patch and use hard-coded queries in grails to write and access data to and from the table.
2. Create a domain class like AccountUser having properties clientId and userId
I choose the 2nd option, I wrote some additional methods and created a service to return user and client instance and I am done ! Anyways, thanks guys.
If the databases are "visible" to each other (on the same server or there is a db link between them), you should be able to map the domain classes using the fully qualified table names ('schema.tablename') in the mapping closure.
psuedocode:
class User {
static mapping = {
table "usermanagement.user"
}
static hasMany = [Account:accounts]
}
class Account {
static mapping = {
table "xyz.account"
}
}
http://grails.org/doc/latest/guide/GORM.html#tableAndColumnNames

add user define properties to a domain class

i have a requirement to allow the user to define some custom field in one of the system entities. do you have any suggestion/pattern/plugin that will help me add this feature to my application.
thanks,
Meni
You can add a Map property to your domain class and store arbitrary data there. It's rather limited though. It will generate a table with varchar(255) keys and values, so you need to manage any type conversions yourself, e.g.
class Thing {
String name
Map extraProperties = [:]
}
int age = 123
def thing = new Thing(name: 'whatever')
thing.extraProperties.age = age.toString()
thing.save()
...
def thing = Thing.get(thingId)
int age = thing.extraProperties.age.toInteger()
See section "5.2.4 Sets, Lists and Maps" at http://grails.org/doc/latest/ for the brief online docs.
Sounds like you want your application to be an infinitely adjustable wrench that users can modify at will. Is that fair?
I don't think it's possible or desirable. Think about what happens when you add an attribute to an existing domain object in Grails. The attribute is added to the ORM mapping, which means the tables have to be modified. The UI has another text box added for data entry; the list page has another column added to its table.
There's a lot going on when you add an attribute. How will you manage multiple users modifying the app all at the same time? What happens when one user is modifying a table while another is accessing the old version?
You ask too much. I don't think it's a reasonable requirement. Grails' sweet spot is rapid development of web-based CRUD applications. I don't think that includes modification by users at runtime.

Resources