GORM - get raw DB value for domain class properties - mongodb

I'm using GORM for MongoDB in my Grails 3 web-app to manage read/writes from DB.
I have the following 2 domain classes:
class Company {
String id
}
class Team {
String id
Company company
}
For teams, their company is saved on DB as String, and with GORM I can simply use team.company to get an instance of Company domain class.
However, I need to override the getter for company, and I need the raw value for company id (as stored on DB), without GORM getting in the way and performing its magic.
Is there a way to get the raw String value?
Any help is welcome! Thanks in advance
Update (May 27)
Investigating #TaiwaneseDavidCheng suggestion, I updated my code to
class Company {
String id
}
class Team {
String id
Company company
String companyId
static mapping = {
company attr: "company" // optional
companyId attr: "company", insertable: false, updateable: false
}
}
Please note that I'm using GORM for MongoDB, which (citing the manual) tries to be as compatible as possible with GORM for Hibernate, but requires a slightly different implementation.
However I found out (by trial&error) that GORM for MongoDB doesn't support a similar solution, as it seems only one property at a time can be mapped to a MongoDB document property.
In particular the last property in alphabetical order wins, e.g. companyId in my example.
I figured out a way to make the whole thing work, I'm posting my own answer below.

given a non-insertable non-updateable column "companyId" in domain class
class Company {
String id
}
class Team {
String id
Company company
Long companyId
static mapping = {
company column:"companyId"
companyId column:"companyId",insertable: false,updateable: false
}
}

(Follows the edit to my question above)
I defined a custom mapping, and made use of Grails transients by also defining custom getter and setter for team's company.
class Company {
String id
}
class Team {
String id
Company company
String companyId
static mapping = {
companyId attr: "company" // match against MongoDB property
}
static transients = [ 'company' ] // non-persistent property
Company getCompany() {
return Company.get(companyId)
}
void setCompany(Company company) {
companyId = company.id
}
}

Related

Hibernate Search add only DocumentId from IndexedEmbedded class

I've an Entity "Invoice" and this one has a many-to-one relationship to Customer-Entity. This Customer-Entity is also used from other Entities for Hibernate Search and so there are many Hibernate Search annotations. For Invoice HS-Index I just want to have the Customer.id in the Invoice index and no other property of Customer.
How is this possible, because in the documentation I've found nothing specific about it.
In recent versions of Hibernate Search, you would simply use #IndexedEmbedded(includePaths = "id").
Hibernate Search 3.4 is very old, though (9 years old), and is missing many features. I'd recommend you upgrade since you're very likely to hit bugs that will never be solved in this version.
If you really have to stick with 3.4, I believe your only solution will be writing a custom bridge:
public class CustomerIdBridge implements StringBridge {
public String objectToString(Object object) {
Customer customer = (Customer) object;
if ( customer == null ) {
return null;
}
Object id = customer.getId();
return id == null ? null : id.toString();
}
}
Then apply the bridge like this:
#ManyToOne(...)
#Field(bridge = #FieldBridge(impl = CustomerIdBridge.class))
private Customer customer;
The resulting field will simply be named "customer" (same name as your property).
See here for more information about bridges in Hibernate Search 3.4.2.

Grails GORM hasMany association inconsistent with MongoDB, When try to fetch child Records,it fetches the record sometimes and doesn't fetch sometimes

Below is the domain class Author which has a one-to-many association with Book. When trying to fetch Author, sometimes will get the associated collection of Book domain object and sometimes returns null. Any thoughts on why it is inconsistent?
class Author {
static mapWith = "mongo"
String name
static hasMany = [books: Book]
}
_author.gson
model {
Author author
}
json g.render(author]) {
books g.render(author.books)
}
Environment details:
grailsVersion=3.3.5
gormVersion=6.1.8.RELEASE
We are using GORM multi-tenancy and using MongoDB database.
I have switched to sub-document model and it's working now. Here is the domain model code.
class Author {
static mapWith = "mongo"
String name
List<Books> book
static embedded = ['book']
}

Grails 3 & relational domain mapping with Mongo

Trying to figure out if there is a way that I can relate these two domain objects in a similar way that I would if I were connected to an Oracle db.
gradle.properties
grailsVersion=3.2.9
gradleWrapperVersion=2.9
gormVersion=6.1.3.RELEASE
build.gradle
compile "org.grails.plugins:mongodb:6.1.3"
compile "org.mongodb:mongodb-driver:3.4.2"
Domain objects:
class Store {
Long id
// other properties
Long sellerId
}
class Seller {
Long id
// other properties
}
I thought to do something like this:
class Store {
Long id
// other properties
Long sellerId
Seller seller
Seller getSeller {
Seller.findById(this.sellerId)
}
}
In the case above, only sellerId is persisted to Mongo since it is not marked as embedded. This works great if I reference it in grails code - giving me valid values for all of the properties in store.seller. However, if I return a store from a controller, store.seller does not come through fully. The response JSON for store looks like this (notice how seller ONLY has the id property):
{
id: 1,
// other properties
seller: {
id: 22
}
}
I have also tried something like this but afterLoad never gets hit:
class Store {
Long id
// other properties
Long sellerId
Seller seller
def afterLoad() {
seller = Seller.findById(this.sellerId)
}
}
Is there a better way to go about doing this?

Eagerly load MongoDB #DBRef in Spring data's RepositoryRestResource

I'm trying to implement a rest api using RepositoryRestResource and RestTemplate
It all works rather well, except for loading #DBRef's
Consider this data model:
public class Order
{
#Id
String id;
#DBRef
Customer customer;
... other stuff
}
public class Customer
{
#Id
String id;
String name;
...
}
And the following repository (similar one for customer)
#RepositoryRestResource(excerptProjection = OrderSummary.class)
public interface OrderRestRepository extends MongoRepositor<Order,String>{}
The rest api returns the following JSON:
{
"id" : 4,
**other stuff**,
"_links" : {
"self" : {
"href" : "http://localhost:12345/api/orders/4"
},
"customer" : {
"href" : "http://localhost:12345/api/orders/4/customer"
}
}
}
Which if loaded correctly by the resttemplate will create a new Order instance with customer = null
Is it possible to eagerly resolve the customer on the repository end and embed the JSON?
Eagerly resolving dependent entities in this case will raise most probably N+1 database access problem.
I don't think there is a way to do that using default Spring Data REST/Mongo repositories implementation.
Here are some alternatives:
Construct an own custom #RestController method that would access the database and construct desired output
Use Projections to populate fields from related collection, e.g.
#Projection(name = "main", types = Order.class)
public interface OrderProjection {
...
// either
#Value("#{customerRepository.findById(target.customerId)}")
Customer getCustomer();
// or
#Value("#{customerService.getById(target.customerId)}")
Customer getCustomer();
// or
CustomerProjection getCustomer();
}
#Projection(name = "main", types = Customer.class)
public interface CustomerProjection {
...
}
The customerService.getById can employ caching (e.g. using Spring #Cachable annotation) to mitigate the performance penalty of accessing the database additionally for each result set record.
Add redundancy to your data model and store copies of the Customer object fields in the Order collection on creation/update.
This kind of problem arises, in my opinion, because MongoDB doesn't support joining different document collections very well (its "$lookup" operator has significant limitations in comparison to the common SQL JOINs).
MongoDB docs also do not recommend using #DBRef fields unless joining collections hosted in distinct servers:
Unless you have a compelling reason to use DBRefs, use manual references instead.
Here's also a similar question.

How to create association one to many and many to one between two entities in gorm?

I'm new in Grails. I have a problem with generation association many to one and one to many between two tables. I'm using postgresql database.
Employee.groovy
class Employee {
String firstName
String lastName
int hoursLimit
Contact contact
Account account
Unit unit
char isBoss
static hasMany = [positionTypes:PositionType, employeePlans: EmployeePlan]
}
EmployeePlan.groovy
class EmployeePlan {
AcademicYear academicYear
HourType hourType
int hours
float weightOfSubject
Employee employee
static belongsTo = [SubjectPlan]
}
I'd like to have access from employee to list of employeePlans and access from EmployeePlan to Employee instance. Unfortunately GORM generates only two tables Employee and EmployeePlan with employee_id. I don't have third table which should have two columns employee_id and employee_plan_id. Could you help me ?
I think your setup is correct, as you write from Employee class you can access to a collection of EmployeePlan (take care, that if you don't explicitly define EmployeePlan like a List, it will be a Set by default) and from EmployeePlan you can access Employee.
If you need List, you can define it like that:
class Employee {
String firstName
String lastName
int hoursLimit
Contact contact
Account account
Unit unit
char isBoss
//explicitly define List
List<EmployeePlan> employeePlans
static hasMany = [positionTypes:PositionType, employeePlans: EmployeePlan]
}
But back to your question. You'd like to have join table between Employee and employeePlan, but why? Its not necessary, since you have bidirectional mapping with sets (unordered), grails will not create a join table. Can you explain why do you need it? In grails the references will be auto-populated, so I don't see any issue here.
If need to preserve order of employeePlans, then define it as List, shown above, and grails will create a join table with corresponding indexes.
have you read the ref-doc? it gives you the answer immediately:
class Person {
String firstName
static hasMany = [addresses: Address]
static mapping = {
table 'people'
firstName column: 'First_Name'
addresses joinTable: [name: 'Person_Addresses',
key: 'Person_Id',
column: 'Address_Id']
}
}