I would like to create a grails domain class that links to itself.
This related post suggests a solution but I can't get it to work: Grails domain class relationship to itself
For one thing I don’t understand what comparable does and would need to add a int compareTo(obj) method.
Adding the following to my code without implementing Comparable compiles, but grails crashes at runtime:
//NavMenu parent
SortedSet subItems
static hasMany = [subItems: NavMenu]
static belongsTo = [parent: NavMenu]
static constraints = { parent(nullable:true) }
Thanks in advance
When you're using SortedSet, a sort algorithm is internally executed, but it needs a sort criteria. You need to implement the Comparable interface because that is the standard way to provide a sort criteria to the internal algorithm.
If you don't need a specific order, you can delete the SortedSet subItems line and thus avoid implementing the Comparable interface.
If you don't want to use Comparable interface, maybe you should use List instead of SortedSet.
With a list you can keep objects in the order which they were added and to be able to reference them by index like an array.
This is an example from official docs:
class Author {
List books
static hasMany = [books: Book]
}
Related
We are a looking for a value type design pattern in swift that will allow us to create a shopping cart to hold Products. We are currently using a class but that is a reference type and when we try to add two different version of the same product (i.e. with a different colors or sizes), the first item we added gets changed to the second item we added because it points to the same object in memory.
The design pattern needs to be “global” so we can access it from any page in the app. Right now this is our Cart class that stores all the items in the cart. What do we need to do to make this a value type or how does it need to be reengineered to use a struct without a class?
class Cart : NSObject {
var allProductsInCart = [MainProduct]()
override init() {
super.init()
}
class var sharedCart: Cart {
struct Static {
static let instance = Cart()
}
return Static.instance
}
}
The problem we are getting is that we need the products in the cart to be of custom class “MainProduct.” Right now as you can see, they are stored as “MainProduct.” Do we need to switch the products to a struct or other design pattern as well? How would we do that?
Yes, given the desired behavior between a value type vs. reference type you should use a Struct.
A commonly used "pattern" for doing this is called "Redux".
The idea is that you have one, immutable version of the "state" of your app.
It can be accessed from anywhere and the only way to update it is through "actions". These will reconstruct the entire state with the required updates.
ViewControllers and views, etc... subscribe to updates of various parts of the state.
So you could have an AppState that contains a ShoppingCartState. When a product is added to it your CartViewController will be informed of this update and can update its view etc...
There are many different frameworks that are built to use Redux so I won't recommend one as you should find the one that is right for you. But I believe this pattern best suits the usage you are after.
For a project I'm currently working on I need to dynamically add properties to a domain class and persist them later in the database. In general, I need a key/value store attached to a "normal" domain class. Sadly I cannot use a NoSQL database (e.g. Redis).
My approach would be to handle the additional properties on a save() by identifying them within afterInsert or afterUpdate and writing them to another table - I would prefer not to use a map property within the domain class but an additional "Field" table (to better support searches).
I tried to add properties using the metaClass approach:
person.metaClass.middlename = "Biterius"
assert person.middlename == "Biterius" // OK
This works and I can identify the additional properties in the afterInsert/afterUpdate methods but it seems that I cannot change the value thereafter - i.e., the following does not work:
person.middlename = "Tiberius"
assert person.middlename == "Tiberius" // FAIL
Then I tried an Expando approach by extending the Person class by the Expando class (directly ("Person extends Expando") and via an abstract intermediate class ("Person extends AbstractPerson" and "AbstractPerson extends Expando")).
def person = new Person()
assert person in Person // OK
assert person in AbstractPerson // OK
assert person in Expando // OK
Both variants did not work - I could assign values to arbitrary "properties" but the values were not stored!
person.mynewproperty = "Tiberius" // no MissingPropertyException is thrown
println person.mynewproperty // returns null
So how can I add properties to a domain class programmatically during runtime, change them and retrieve them during afterInsert or afterUpdate in order to "manually" store them in a "Fields" table?
Or am I doing something completely wrong? Are there other / simpler ways to do this?
What about turning your DB into a "NoSQL" one?
In one of my projects, I just used a String-property to store a map as JSON-Object.
For Groovy it's not a big problem to convert between a map and a JSON-Object. And since you can access a map just like an object with properties, I found this solution very convenient.
Only drawback: you have to plan the size of your String-property in advance...
Update: sorry, just read that you want to support searches...
what about
class Person {
...
static hasMany = [extProperties:KeyValue]
...
def invokeMethod(String name, args) {
if (name.startsWith('get')) {
//an unknown properties's getter is called
}
//add same for setter
}
}
class KeyValue {
String key
String value
}
I guess such a schema would give you all freedom you need. Even without the hasMany, you can make use of invokeMethod to handle your external tables...
The getter and setter can save your values in a transient string propertie (static transients = ['myTransientProperty']). This property should be available in the afterInsert / `afterUpdate´ events.
Why don't you just create a map of strings on the domain object and store your extra data there manually? Unless you're storing complex data you should be able to cast anything you need to/from a string.
I hope you can help me guys. Google unfortunately didn't helps me out and my search here at stackoverflow didn't as well :-(
I have two DomainClasses HumanResource and Task with a many-to-many relationship.
Model-Definitions:
Task:
class Tasks {
String name
static belongsTo = [HumanResource]
static hasMany = [humanResources: HumanResource]
//also tried but didn't help -> static fetchMode = [humanResources:"eager"]
}
HumanResource:
class HumanResource {
String name
static hasMany = [tasks: Tasks]
}
I also tried to add an index on the id-field with mapping={} but I also think that's not the solution, it didn't help and I think there is already an index on the id-field.
So, what I did and not works is now to find all human resources for the given tasks! And the tasks comes from Services and they are already fetched in the service model with "static fetchMode = [tasks:"eager"]"!
Controller-Code:
def listHumanResourcesFromTasks = {
def list = HumanResource.findAllByTasks(service.getTasks())
//and I tried also with an own HashMap but didn't work as well
}
I always get an error "org.springframework.dao.InvalidDataAccessResourceUsageException" with an SQL-GrammarException. But I really don't know why. The "service.getTasks()" objects are fully filled (as I wrote with fetchMode = [tasks:"eager"])...
It would be awesome if somebody could give me the winning hint.
Thanks a lot for your time.
Best wishes,
Marco
This sort of query isn't supported - you'd need to use HQL or a criteria query in general. But this particular one is easy since you have a bidirectional relationship. You can get all of the HumanResource instances for a collection of Tasks with this:
def resources = service.getTasks().collect { it.humanResources }.flatten() as Set
It needs to be a Set since the same HumanResource instance may appear multiple times so you need to condense the List into unique instances.
It seems that there are two different ways of declaring sorted associations in Grails :
Method 1 (see here) using default sort order
class Book {
String title
}
class Author {
static hasMany = [books : Book]
static mapping = { books sort: "title"}
}
Method 2 (see here) using SortedSet
class Book implements Comparable {
String title
int compareTo(obj) {
title <=> obj.title
}
}
class Author {
SortedSet books
static hasMany = [books : Book]
}
I am not sure which one to use and what is the difference (if any), pros and cons between using one against the other.
I would appreciate any clarification.
Thank you
I started to dig into how this all works and then found that method 1 is actually busted in current versions of grails (tested in both 1.2.1 and 1.3). When you actually try to retrieve an author and look at it's books, it throws an exception
There is an open defect for it (4089) which has been open for quite a while.
Here's the exception that gets thrown:
ERROR util.JDBCExceptionReporter - Column not found: BOOKS0_.TITLE in statement [select books0_.author_books_id as author1_0_, books0_.book_id as book2_0_ from author_book books0_ where books0_.author_books_id=? order by books0_.title]
If and when they finally fix it, the differences between the two methods are that in method one, sorting is done at the database level. As you can see in the exception above, GORM was trying to do an "order by books0_.title" which would use any database index on the book.title field and return the objects in that order.
The second method would sort the objects in memory at the time that they get inserted into the set (using the compareTo method that was defined).
Until the current bug is fixed, I'd use method 2 because it's the only thing that works. It should be fine for relatively small collections of things. After it's fixed, I'd potentially prefer method 1 as the database should be quicker at doing the sorting with an index on the sort field.
Is it possible to set the database column type of a hasMany association to a primitive type (in my case string) to a specific value? I know how to set a field (see this question), but this is different.
List textRecords
static hasMany = [
textRecords:String,
]
I want to make sure that my textRecords are mapped to a TEXT or LONGTEXT database type.
I could create a separate domain class that contains just one string field and map that field, but that seems like a kluge.
The Grails User Guide has an example listed in 5.2.1.4 Basic Collection Types section that is very similar to what you want to accomplish.
Keep in mind that every time you want to add a textRecord to that object it will have to load the entire List of textRecords in order to save it again. This may not be the behaviour that you want for performance reasons.
You'll end up having a mappings block like this:
static mapping = {
hasMany joinTable:[name:'bunch_o_text_records', key:'domain_id', column:'text_record', type:"text"]
}