Grails - Multiple Tables in Single Domain Class - grails

I have two tables with a common primary key. Now i want to get data from that both tables and show in single view using that primary key.
How i can get both table data in single domain class? How can i specify mapping?
For Example
Table-A and Table-B both are in single schema ABC
class X {
int id
String name
static mapping = {
table name: "Table-A", schema: "ABC"
columns {
name column:'name'
}
}
}
now i want to get address from table-B so that my view looks like below
ID NAME ADDRESS
2 HSJHD 23 X-Street Washington USA
How to get two table data in single domain class?

This sounds like a foreign key relation, you would simply use belongsTo in each object (provided a one-to-one relationship).
http://grails.org/doc/latest/ref/Domain%20Classes/belongsTo.html
Otherwise you could create a database view on your database, then create a domain object to match that view. Creating a domain based on a database view is identical to creating a domain based on a table.

Few options
Just use hql to query and join on the primary key
Create a view from the two tables, and map new table to that view
Use belongs to and when u access one object then access the other

You will need to use constraints: http://www.grails.org/doc/2.0.x/ref/Constraints/Usage.html
and http://www.grails.org/doc/2.0.x/guide/single.html#constraints

Related

How to model stored procedure records in Grails?

I need to call some stored procedures that return their own kinds of records, that are not directly mapped to tables or views.
I have used stored procedures in the past with groovy.sql.Sql and plain (unmodelled) Maps, but for this application I would like to model those records with something akin to domain classes, in order to define data types, data binding, validation, associations to other entities, and so on.
What is the best way to do so?
Should I model the stored procedure records as proper domain classes (entities) and then try to disable (or redefine) their database persistence? How?
Should I use non-domain POJOs where I selectively enable the features I need? (such as validation with #Validatable) How can I handle associations then? (Associations arise when the record returned from the SP contains a foreign key to some other persisted entity.)
If you want data binding, validation and associations to be maintained in an easy way then you should go with the Domain approach.
To disable database persistence for a domain class you can add static mapWith = "none" to a domain class and a table won't be created for that domain class.
Sample Entity class:
#ToString
public class SPTest {
Long idField
User user
GroupIntegrationKey integrationKey
static constraints = {
}
static mapWith = "none"
}
Stored Procedure statement:
SELECT id AS idField, user_id AS user, key AS integrationKey FROM
my_domain;
In order to map the result of the SP to the entity you can use result transformers.
Query query = session.createSQLQuery("CALL getSPData()");
List<Map> results = query.with {
resultTransformer = AliasToEntityMapResultTransformer.INSTANCE
list()
}
Now iterate over list and create a new entity object
List<MyDomain> list = results.collect {
new MyDomain(it)
}
System.err.println(list)
Drawbacks:
You can not map identifier field
You would have to iterate over result again to create entity objects
You can not map hasMany relationships
If you want to go with pojo, then in that case you would have to create your own version of getters to get associated objects.

GORM and Composite Keys in associations

I have legacy database and some tables have composite ids
class Client {
String id
static hasMany = [
settings: Setting
]
static mapping = {
id column: 'client_id', generator: 'assigned'
}
}
class Setting {
Client client
String nodeId
String ccyPairPattern
Character qualifier
static mapping = {
id composite: ['client', 'nodeId', 'pattern', 'qualifier']
}
}
I want to delete entry from GORM association:
client.get('1').removeFromSettings(settingToRemove)
// settingToRemove.delete(flush: true)
// delete-orphans does not help
This always raises exception after flush
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) :
This happens because method removeFrom* sets client property to null and generates query to delete with clientId = null as client is part of composite key
What is the best solution in this case. Looks like GORM has poor support for composite keys or my mapping is incorrect.
When you use hasMany without a belongsTo on the many side, in other words a unidirectional association, you get a join table. For example...
class PurchaseOrder {
static hasMany = [items: Item]
}
class Item { }
Would yield three database tables: purchase_order, item, and purchase_order_items. The purchase_order_items table would contain two columns: purchase_order_id and item_id. You can read more about join tables here.
Since you're dealing with a legacy database, I think the best solution is not to use addTo*() and removeFrom*().
Ensure you don't have a join table. If you have a join table, remove the hasMany association.
You'll need to add/remove Setting instances manually.
Example:
def client = Client.get(1)
// Adding a setting
def setting = new Setting(client: client, nodeId: blah...)
setting.save()
// Removing a setting
/*
The prototype is used to search for a domain instance with a composite primary key.
So simply set the composite key properties accordingly.
*/
def prototype = new Setting(client: client, nodeId: blah...)
def setting = Setting.get(prototype)
setting.delete()
Lacking a hasMany association, you won't be able to access a client's settings via the client.settings property. Instead you'd have to query for them like this:
def settings = Setting.findByClient(client)
A consequence of using a legacy database is that if the database doesn't align with that GORM/Hibernate expects it will be limited in what it can do for you.

GORM: embed a class containing a reference to a domain class

Given:
User, File are domain classes
src/groovy/Container.groovy:
class Container {
User user
File file
Date dateCreated
}
grails-app/domain/WithContainer.groovy:
class WithContainer {
Container c
String text
static embedded = ['c']
}
I was aiming at mapping WithContainer to a table with the columns:
user_id | file_id | date_created | text
Is that achievable with GORM?
This setup yields:
org.hibernate.MappingException: Could not determine type for: User, at table: with_container, for columns: [org.hibernate.mapping.Column(c_user)]
Thanks
Container is not a domain class because it isn't defined under grails-app/domain/.
It may be that you are confused about the embedded attribute. Properties in the embedded list are persistent properties for which you want all of their attributes stored in the same table as the owning class (WithContainer in your case), as opposed to being stored in their own table and referenced with foreign keys. The property still needs be an instance of a domain class though.

Access Relationship Table in Grails

I have the following domains classes:
class Posts{
String Name
String Country
static hasMany = [tags:Tags]
static constraints = {
}
}
class Tags{
String Name
static belongsTo = Posts
static hasMany = [posts:Posts]
static constraints = {
}
String toString()
{
"${TypeName}"
}
}
Grails creates an another table in the database i.e. Posts_Tags.
My requirement is:
E.g. 1 post has 3 tags.
So, in the Posts_Tags table there are 3 rows.
How can I access the table Posts_Tags directly in my code so that I can manipulate the data or add some more fields to it.
If you want to access the join table (Posts_Tags) directly, or add properties to it, then you must define it as a separate PostTag domain class. You then split your many-many relationship between Post and Tag into 2 one-to-many relationships (one from Post to PostTag and one from Tag to PostTag).
Here's a comprehensive example of how to perform the mapping and add properties to the join table - in this example Membership is the join table.
Use the normal groovy sql API. For an example of how to get a groovy SQL object and execute sql queries see this

How would nhibernate handle tables that aren't really entities per se?

I understand how nhibernate would map a table like Users, and Addresses.
But what if I have a table like:
Users_Addresses with columns UserID, AndressID.
Would I have to create a mapping for this and make it like a normal entity? It is really a table that I would reference in a inner join.
With NHibernate, you design your code independent of the database layout. You don't have to (and don't should to) create classes that are exactly the same as your database tables and columns.
Example:
public class User
{
public IList<Address> Addresses { get; private set; }
public int Id { get; set; }
}
The mapping depends on what the relationship between address and user is:
Can a user have multiple addresses?
Can multiple users have the same address?
What do you want to inner join on what? (I would expect a many to many
relationship here with an outer join)
In a scenario when a user has multiple addresses and those addresses can be used by different users, you can use many to many mapping to map the address.
The mapping also depends on how you want to create your user and address classes.
Is it logical to have a list of addresses in a user?
Is it logical to have a list of users in an address?
Can a user have the same address twice?
The idea of NHibernate is: write code the way you like it, and add mapping to a database to it later.
Address is usually considered a value type in the scenario you are discussing - it has no intrinsic identity outside of the User.
Value types in nHibernate are mapped as components. Collections of value types are mapped as a set of composite elements.
See https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/components.html for details on how to do this.

Resources