I was reading over the docs regarding Eclipselink's support for #OrderColumn. It looks like this only applies to List and not Set. The reason I ask is because I have a ManyToMany bi-directional relationship (using a join table) which is a Set and is implemented with a HashSet because the collection can't have duplicates.
I wanted to order the entries in this set using #OrderColumn, but it appears I can only apply this to List, however using List will break my unique requirement. Is this understanding correct?
If so what is the recommended strategy for this case?
Thanks,
-Noah
This looks similar to the following question:
Why cannot a JPA mapping attribute be a LinkedHashset?
The Set interface does not define ordering of elements, so your set needs to be a concrete implementation like a TreeSet or LinkedHashSet implementation, not just any old Set. But your JPA provider is generally going to use its own collection implementations with special magic to handle lazy loading.
The above answer suggests that there may be some EclipseLink-specific workaround if you are willing to give up lazy loading.
I can think of two options, neither one perfect:
just use a List and rely on business logic to enforce uniqueness, with DB UNIQUE constraints as a backstop. Honestly, I end up using List for collections almost reflexively, even when Set would have been more appropriate; I admit it's sloppy but has yet to cause any significant problems for me in years of practice.
use a Set and change #ManyToMany to #OneToMany, and make your join table w/order column an actual entity that implements Comparable using the order column. Then, overload your getter method to do something like
if (! this.set instanceof TreeSet)
this.set = new TreeSet<T>(this.set);
return this.set;
Related
Ok, so here [1] is the great read, how do really correctly define hashcode/equals, namely with respect to object hierarchies. But here I'd like to ask about #pitfall 3 from that article, which shows bizarre behavior when hashcode/equals are defined on mutable fields and Set is used for collections. We cannot use final fields and parameterized constructor only, due to JPA spec. So what are the means to avoid these gotchas? What do you use?
Well, obviously one is to avoid using Set in JPA entities. Does not seems very nice. Another solution could be to "unsupport" setters after equals method was called, but that's ridiculous and equals surely shouldn't have side-effect.
So how do you cope with that? Aside from not-knowing/ignoring it, which probably would be default action in java world...
[1] https://www.artima.com/lejava/articles/equality.html
If entity is detached you need to override equal and hashcode1. Every entity has to have #Id. ID is immutable. Entities should implement equal and hashcode based on primary key ID.
Pitfall 3 deals with mutable object. Cannot by applied on entity with immutable ID.
Guide to Implementing equals() and hashCode() with Hibernate
According to the spec, when #IndexedEmbedded points to an entity, the association has to be directional and the other side has to be annotated with #ContainedIn. If not, Hibernate Search has no way to update the root index when the associated entity is updated.
Am I right to assume the word directional should be bi-directional? I have exactly the problem that my index is not updated. I have one-directional relationships, e.g. person to order but the order does not know the person. Now when I change the order the index is not updated.
If changing the associations to become bi-directional is no option which possibilities would I have to still use hibernate-search? Would it be possible to create two separate indices and to combine queries?
Am I right to assume the word directional should be bi-directional?
Yes. I will fix this typo.
If changing the associations to become bi-directional is no option which possibilities would I have to still use hibernate-search?
If Person is indexed and embeds Order, but Order doesn't have an inverse association to Person, then Hibernate Search cannot retrieve the Persons that have to be reindexed when an Order changes.
Thus you will have to reindex manually: https://docs.jboss.org/hibernate/search/5.11/reference/en-US/html_single/#manual-index-changes .
You can adopt one of two strategies:
The easy path: reindex all the Person entities periodically, e.g. every night.
The hard path: reindex the affected Person entities whenever an Order changes. This basically means adding code to your services so that whenever an order is created/updated/deleted, you run a query to retrieve all the corresponding persons, and reindex them manually.
The first solution is fairly simple, but has the big disadvantage that the Person index will be up to 24 hours out of date. Depending on your use case, that may be ok or that may not.
The second solution is prone to errors and you would basically be doing Hibernate Search's work.
All in all, you really have to ask yourself if adding the inverse side of the association to your model wouldn't be better.
Would it be possible to create two separate indices and to combine queries?
Technically, if you are using the Lucene integration (not the Elasticsearch one), then yes, it would be possible.
But:
you would need above-average knowledge of Lucene.
you would have to bypass Hibernate Search APIs, and would need to write code to do what Hibernate Search usually does.
you would have to use experimental (read: unstable) Lucene APIs.
I am unsure as to how well that would perform, as I never tried it.
So I wouldn't recommend it if you're not familiar with Lucene's APIs. If you really want to take that path, here are a few pointers:
How to use the index readers directly: https://docs.jboss.org/hibernate/search/5.11/reference/en-US/html_single/#IndexReaders
Lucene's documentation for joins (what you're looking for is query-time joins): https://lucene.apache.org/core/5_5_5/join/org/apache/lucene/search/join/package-summary.html
Consider you are doing some integration testing, you are storing some bigger entity into db, and then read it back and would like to compare it. Obviously it has some associations as well, but that's just a cherry on top of very unpleasant cake. How do you compare those entities? I saw lot of incorrect ideas and feel, that this has to be written manually. How you guys do that?
Issues:
you cannot use equals/hashcode: these are for natural Id.
you cannot use subclass with fixed equals, as that would test different class and can give wrong results when persisting data as data are handled differently in persistence context.
lot of fields: you don't want to type all comparisons by hand. You want reflection.
#Temporal annotations: you cannot use trivial "reflection equals" approaches, because #Temporal(TIMESTAMP) java.util.Date <> java.sql.Date
associations: typical entity you would like to have properly tested will have several associations, thus tool/approach ideally should support deep comparison. Also cycles in object graph can ruin the fun.
Best solution what I found:
don't use transmogrifying data types (like Date) in JPA entities.
all associations should be initialized in entity, because null <> empty list.
calculate externaly toString via say ReflectionToStringBuilder, and compare those. Reason for that is to allow entity to have its toString, tests should not depend that someone does not change something. Theoretically, toString can be deep, but commons recursive toStringStyle includes object identifier, which ruins it.
I though, that I could use json format to string, but commons support that only for shallow toString, Jackson (without further instructions on entity) fails on cycles over associations
Alternative solution would be actually declaring subclasses with generated id (say lombok) and use some automatic mapping tool (say remondis mapper), with option to overcome differences in Dates/collections.
But I'm listening. Does anyone posses better solution?
I have table name Transaction in the DB. I want to have 2 subclasses TransactionA and TransactionB. I've made it as described here: http://www.robbagby.com/entity-framework/entity-framework-modeling-table-per-hierarchy-inheritance/comment-page-1/#comment-607
The problem is I need to use the field that is discriminator here (see the example, it's PersonCategory there). But it has to be deleted after that I cannot use it.
How to solve this problem?
Thanks
If it is a discriminator its only usage is to map record to either TransactionA or TransactionB. It cannot be set in the application. It is set if you insert TransactionA instance or TransactionB instance and record. It also cannot be updated because object of one type cannot change to object of other type - if you need such logic you cannot model it as inheritance.
Yes it is used as a EF helper to identify type of the specific type of the object. One disadvantage is that approach is every field should be a nullable field and tables are not normalized. However, no joins are involved hence, it is fast approach. Table per type is relatively good approach you have two classes TransactionA and TransactionB with generic class called Transaction.Although, you have to do join as a result of that, performance is not that great compair to earlier approach.
I'm using DataNucleus as a JPA implementation to store my classes in my web application. I use a set of converters which all have toDTO() and fromDTO().
My issue is, that I want to avoid the whole DB being sent over the wire:
If I lazy load, the converter will try to access ALL the fields, and load then (resulting in very eager loading).
If I don't lazy load, I'll get a huge part of the DB, since user contains groups, and groups contains users, and so on.
Is there a way to explicitly load some fields and leave the others as NULL in my loaded class?
I've tried the DataNucleus docs with no luck.
Your DTOs are probably too fine-grained. i.e. dont plan to have a DTO per JPA entity. If you have to use DTOs then make them more coarse grained and construct them manually.
Recently we have had the whole "to DTO or not to DTO, that is the question" discussion AGAIN. The requirement for them (especially in the context of a JPA app) is often no longer there, but one of the arguments FOR DTOs tends to be that the view has coarser data requirements.
To only load the data you really require, you would need to use a custom select clause containing only these elements that you are about to use for your DTOs. I know how painful this is, especially when it involves joins, which is why I created Blaze-Persistence Entity Views which will take care of making the query efficient.
You define your DTO as an interface with mappings to the entity, using the attribute name as default mapping, this looks very simple and a lot like a subset of an entity, though it doesn't have to. You can use any JPQL expression as mapping for your DTO attributes.