Syntax for "addAll()" to list in grails? - java

In java, if I have a list, I can use addAll(otherList); to add all the elements from one list to another.
What is the equivalent in grails? I have a Domain object with a hasMany relationship. To add to it, I would use something like
Object.addToMyList(someitem);
and it seems like
Object.addAllToMyList(otherList)
does not exist.
What is the equivalent in grails?

To clarify - by default the collection is a Set, but addAll() works with any Collection.
You can call addAll() and it'll work fine, although the back-references won't be set if it's bidirectional. This doesn't affect persistence, just the current in-memory state.
There's nothing built into GORM for this, so I suppose the "right" way is a loop, e.g.
otherItems.each { foo.addToBars(it) }

Related

Putting all returned elements into a Spring-Boot cache using annotations

Using spring-boot and its caching mechanism, is it possible to automatically store all entities returned as a collection into the cache one by one?
For instance picture the following Repository method:
#Query("...")
List<Foo> findFooByBar(Bar bar);
I'd like to insert these in a Spring Cache, one by one, meaning there would be N insertions (one for each element in the list) rather than just one (the whole list).
Example:
#Query("...")
#CachePut(value = "foos", key = "result.each.id")
List<Foo> findFooByBar(Bar bar);
Sometime ago, another person asked a similar/related question on SO and I provided an answer along with an example.
As you know, by default, out-of-the-box Spring does not handle multiple keys/values in the way that you suggested, though I like your thinking here and your example/UC is valid.
Often times, however, you can achieve what you want using an intermediate solution with just a bit of extra work. Spring is an excellent example of the Open/Closed principle and the 2 primary abstractions in Spring's Cache Abstraction is the Cache and CacheManager interfaces.
Typically, you can pick an existing implementation and "adapt" either the Cache or the CacheManager, or both, as I have done in my example.
Though not as ideal or convenient, hopefully this will give you some ideas until perhaps SPR-15213 is considered (though maybe not).
Cheers,
John

What collections does jpa return?

Does JPA ( Eclipselink in this case) always return IndirectList where Entity have a List?
Is ok that list or It should be converted to another list( maybe linkedlist)?
Analysis
If we look at EclipseLink's IndirectList's API, it says:
To use an IndirectList: declare the appropriate instance variable with type IndirectList (jdk1.1) or Collection/List/Vector (jdk1.2).
TopLink will place an IndirectList in the instance variable when the
containing domain object is read from the datatabase. With the first
message sent to the IndirectList, the contents are fetched from the
database and normal Collection/List/Vector behavior is resumed.
If we view IndirectList sources, we will see, that all the work is delegated to it's original collection, just like API says.
Answers
Does JPA ( Eclipselink in this case) always return IndirectList where Entity have a List?
Yes, it always does return your specified collection wrapped with IndirectList. Since it delegates all its internal work to the wrapped collection, it preserves the way it works.
Is ok that list or It should be converted to another list( maybe
linkedlist)?
Yes, it is okay to use IndirectList. You don't convert, you just define any type of collection you want and don't worry about IndirectList, since it is managed transparently.
Since List is an interface the JPA provider is free to return any implementation. EclipseLink rerurns an IndirectList where a List is used. This is perfectly fine since the IndirectList is a List.
For the record or for future reference, it is generally best practice to use interfaces with JPA.

structure for holding data in this instance (Hashmap/ArrayList etc)?

Best way to describe this is explain the situation.
Imagine I have a factory that produces chairs. Now the factory is split into 5 sections. A chair can be made fully in one area or over a number of areas. The makers of the chairs add attributes of the chair to a chair object. At the end of the day these objects are collected by my imaginary program and added into X datatype(ArrayList etc).
When a chair is added it must check if the chair already exists and if so not replace the existing chair but append this chairs attributes to it(Dont worry about this part, Ive got this covered)
So basically I want a structure than I can easily check if an object exists if not just straight up insert it, else perform the append. So I need to find the chair matching a certain unique ID. Kind of like a set. Except its not matching the same object, if a chair is made in three areas it will be three distinct objects - in real life they all reperesent the same object though - yet I only want one object that will hold the entire attribute contents of all the chairs.
Once its collected and performed the update on all areas of the factory it needs iterate over each object and add its contents to a DB. Again dont worrk about adding to the DB etc thats covered.
I just want to know what the best data structure in Java would be to match this spec.
Thank you in advance.
I'd say a HashMap: it lets you quickly check whether an object exists with a given unique ID, and retrieve that object if it does exist in the collection. Then it's simply a matter of performing your merge function to add attributes to the object that is already in the collection.
Unlike most other collections (ArrayList, e.g.), HashMaps are actually optimized for looking something up by a unique ID, and it will be just as fast at doing this regardless of how many objects you have in your collection.
This answer originally made reference to the Hashtable class, but after further research (and some good comments), I discovered that you're always better off using a HashMap. If you need synchronization, you can call Collections.synchronizedMap() on it. See here for more information.
I'd say use ArrayList. Override the hashcode/equals() method on your Chair object to use the unique ID. That way you can just use list.contains(chair) to check if it exists.
I'd say use an EnumMap. Define an enum of all possible part categories, so you can query the EnumMap for which part is missing
public enum Category {
SEAT,REST,LEGS,CUSHION
}

Converting Between Hibernate Collections and My Own Collections

I have set up Hibernate to give me a Set<Integer> which I convert internally to and from a Set<MyObjectType> (MyObjectType can be represented by a single integer). That is to say, When Hibernate calls my void setMyObjectTypeCollection(Set<Integer> theSet) method I iterate through all the elements in theSet and convert them to MyObjectType. When Hibernate calls my Set<MyObjectType> getMyObjectTypeCollection() I allocate a new HashSet and convert MyObjectTypes to Integers.
The problem is that every time I call commit, Hibernate deletes everything in the collection and then re-inserts it regardless of whether any element of the collection has changed or even that the collection itself has changed.
While I don't technically consider this a bug, I am afraid that deleting and inserting many rows very often will cause the database to perform unnecessarily slowly.
Is there a way to get Hibernate to recognize that even though I have allocated and returned a different instance of the collection, that the collection actually contains all the items it used to and that there is no need to delete and reinsert them all?
I think the best way to achieve your goal would be to use a UserType. Basically it lets you handle the conversion from SQL to your own objects (back and forth).
You can see an example on how to use it here.

Is it valid for Hibernate list() to return duplicates?

Is anyone aware of the validity of Hibernate's Criteria.list() and Query.list() methods returning multiple occurrences of the same entity?
Occasionally I find when using the Criteria API, that changing the default fetch strategy in my class mapping definition (from "select" to "join") can sometimes affect how many references to the same entity can appear in the resulting output of list(), and I'm unsure whether to treat this as a bug or not. The javadoc does not define it, it simply says "The list of matched query results." (thanks guys).
If this is expected and normal behaviour, then I can de-dup the list myself, that's not a problem, but if it's a bug, then I would prefer to avoid it, rather than de-dup the results and try to ignore it.
Anyone got any experience of this?
Yes, getting duplicates is perfectly possible if you construct your queries so that this can happen. See for example Hibernate CollectionOfElements EAGER fetch duplicates elements
I also started noticing this behavior in my Java API as it started to grow. Glad there is an easy way to prevent it. Out of practice I've started out appending:
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
To all of my criteria that return a list. For example:
List<PaymentTypeAccountEntity> paymentTypeAccounts = criteria()
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
If you have an object which has a list of sub objects on it, and your criteria joins the two tables together, you could potentially get duplicates of the main object.
One way to ensure that you don't get duplicates is to use a DistinctRootEntityResultTransformer. The main drawback to this is if you are using result set buffering/row counting. The two don't work together.
I had the exact same issue with Criteria API. The simple solution for me was to set distinct to true on the query like
CriteriaQuery<Foo> query = criteriaBuilder.createQuery(Foo.class);
query.distinct(true);
Another possible option that came to my mind before would be to simply pass the resulting list to a Set which will also by definition have just an object's single instance.

Categories