I have an entity with the following field:
#ManyToMany(cascade = { CascadeType.ALL }, targetEntity = Comment.class)
#JoinTable(name = "program_to_comment")
#OrderBy("position")
private Set<Comment> comments = new HashSet<Comment>();
but I have the problem that whenever I persist it using:
Program p = entityManager.persist(entity);
the field comes with the objects sorted as it was sorted in the entity object.
Suppose the entity object is configured as following: Program(comments:[Comment(position:15), Comment(position:10)], ...), persisting the entity (entityManager.persist), it will store both comments and the program entity itself to the database. But the resulted entity from the persist method invocation is an object as follows: Program(comments:[Comment(position:15), Comment(position:10)], ...), in the same order gave to the persist method.
From my point of view at this point the resulted entity should present the values following the specified #OrderBy rule, or am I missing something?
Additional information:
JPA2
Hibernate 4.2.0.Final
OrderBy simply add an order by clause to the query used to load the comments of a program. Nothing more. The rest is under your responsibility. So if you want the comments sorted by position when adding comments and persisting them, you have to take care of this by yourself.
I have personally never found this annotation to be really useful. I have also found it not to work in every case, particularly when using a query to fetch programs with their comments, with an order by clause already present in the query. I generally prefer not to use theis annotation, and provide a getSortedComments() method which returns a sorted set or list of comments, using a comparator.
Related
I have mapped an 1:N relation with a #OneToMany List, but when I access the list, the results are duplicated due to an OUTER JOIN.
This is how the mapping looks like:
#Entity
public class Programmer
#ElementCollection(fetch=FetchType.EAGER)
#CollectionTable(name="emails", joinColumns=#JoinColumn(name="id", nullable=false))
#Column(name="email", nullable=false)
protected Set<String> emails = new HashSet<String>();
#OneToMany(mappedBy="programmer", fetch=FetchType.EAGER)
private List <Game> games = new ArrayList<Game>();
When I get the attribute with prog.getGames(), the results comes duplicated because the Hibernate SQL makes an OUTER JOIN:
from programmer
left outer join emails on programmer.id=emails.id
left outer join game on programmer.id=game.id
where programmer.id=?
Is there any solution without transforming the List into a Set? I need to get the games with prog.getGames(), can not use a custom HQL or Criteria.
While the use of Set<> fundamentally resolves your issue, I'd argue that is simply a bandaid to get the expected results you're after but it doesn't technically address the underlying problem.
You should ultimately be using the default lazy fetch strategy because I'm of the opinion that eagerly loading any associations, particularly collection-based ones, are specific to a query and therefore should be toggled when you construct specific queries and not influenced as a part of your entity mapping model as you're doing.
Consider the future where you add a new query but you're only interestesd in attributes from the aggregate root entity. Your mapping model will still impose eagerly fetching those associations, you'll consume additional resources to by having a larger persistence context which means more memory consumption and impose unnecessary database joins for something which you aren't going to use.
If there are multiple collections that you need to hydrate, I would instead recommend you consider using FetchMode.SUBSELECT instead.
If we assume your query has 10 entities being returned, the default lazy strategy with 2 collections would issue 21 queries (1 for the base result set and 2 for each loaded entity).
The benefit of SUBSELECT is that Hibernate will actually only issue 3 queries (1 for the base result set and 1 for each collection to load all collection elements for all entities). And obviously, depending on certain queries, breaking one query with left-joins into 3 queries could actually perform better at the database level too.
Ive resolved this problem with #Fetch(FetchMode.SUBSELECT)
#OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Fetch(FetchMode.SUBSELECT)
private List<CompanyUserEntity> companyUserRelations;
I had the same problem. companyUserRelations had duplicate objects (I mean the same pointers to the same object, not duplicated data)
So after reading #dimitry response, I added #Fetch(FetchMode.SUBSELECT) and it worked
One of our model object in our application has many fields configured to be eagerly fetched like so:
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "field")
public Field getField() {
return this.field;
}
However I sometime do not need these information, which slow down my queries for nothing. I cannot change the behaviour and use FetchType.LAZY instead as I've no idea what will be the impact on the whole application (legacy...). Is there a way to simply tell hibernate to fetch nothing, except if it is specified in the query?
Last time I checked there was no proper solution provided by hibernate, so I ended up with this solution:
Configured the problematic references as LAZY.
All affected service methods (that used these models) got an overloaded version with boolean forceEager
by default all existing functions were refactored to call the new ones with forceEager=true
and here comes the trick: as a means of "forcing the eager fetching" I found nothing better than actually accessing the proxied (lazy-fetched) objects. In case for example a lazily referenced list doing list.size() will force Hibernate to load the full list, hence the service returns with fully fetched object.
In case of more than one layer in your objectstructure is affected, you need to traverse through the whole hierarchy and access every lazily loaded object from top to bottom.
This is a bit error-prone solution, so you need to handle it with care.
If its possible to switch to Criteria for this query, you could use FetchMode.SELECT for the field property
crit.setFetchMode("field", FetchMode.SELECT);
I have a set of entities that that build some sort of graph. This is modelled by a class Entity with two fields modelling the relationships between entities.
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "fromId")
private Set<EntityRelation> outEdges;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "toId")
private Set<EntityRelation> inEdges;
All outEdges are supposed to belong to the entity when it is saved, the inEdges are "inferred" from these. Problem is then after removing an out-edge I always get an error ERROR: null value in column "fromid" violates not-null constraint where fromid is a field of EntityRelation.
For performance reasons, I don't want to have direct relations form Entity to Entity.
To fix this, I used a new Spring-Data JPA method (in the corresponding Repository class) to explicitly remove everything an entity points to (like
#Modifying
#Query(value = "delete from entityrelation where fromid = ?1", nativeQuery = true)
int deleteEntityRelations(String entityId);
But this somehow misses the whole point, since I want JPA to take responsibility of that.
what is wrong here? I really got stuck, since all posts I could find suggest that it should simply work with orphan-delete.
In the SQL-Trace you can see that an org.hibernate.SQL - update EntityRelation set fromId=null where fromId=? and id=? is issued automatically (which then triggers the error).
thanks and regards
fricke
This is a known issue of hibernate. In certain scenarios (and you found one of them) it violates constraints on foreign key relations. There are various options (but I'm afraid you might not like any of them)
remove the constraint. I know, I know ..
make the constraint deferred. Not sure if this feature is available in other databases but Oracle.
limit the expectations to JPA. Seriously, it looks like you expecting more from it then it will give you. I highly recommend reading this article before proceeding with any project using any kind of ORM.
Please note that even though setting hbm2ddl.auto to UPDATE, it doesn't remove the not-null type constrains when the nullable in entity is set to FALSE. I would suggest that check the history of the class for any changes to entity relationship or column mapping for nullable constraint.
If anybody is looking for the solution, updatable=false in the JoinCoulum annotation fixed this problem for me
#JoinColumn(name = "fromId", updatable = false)
I'm trying to avoid hibernate's lazy-loading mechanism and I've created this list object with the Eager FetchType, which I would suppose would do it:
#JsonIgnore
#CollectionTable(name = "nav", joinColumns = #JoinColumn(name="conn"))
#ElementCollection(fetch = FetchType.EAGER)
#IndexColumn(name="filter") private List<String> filters = Lists.newArrayList();
But I'm still reading a PersistentList, instead of java.util.List. Any idea on what may be wrong ?
I'm not using xml configurations.
A Persistent List is a non-lazy collection that Hibernate uses to correctly store and retrieve data from the databases. It is not a case that when you define your persistable entities you cannot use Java collection implementations, such as ArrayList or LinkedList, but only interfaces. In fact, you are asking for a List and you are getting PersistentList, which totally respect the contract of the interface.
If you remove the eagerness and debug your class, you will see a lazy collection appearing, and this is typically a CGLIB proxy.
To avoid lazy loading you have to set lazy = true and instead of FetchType.EAGER make it FetchType.JOIN.
for annotations based mapping refer to the below link:
[http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/#entity-hibspec-singleassoc-fetching]
let me know if it helps you.
I'm using JPA 1, Hibernate and Oracle 10.2.0 and my entities are defined like this:
#Entity
#Table(name="TERMS")
public class Term implements Serializable {
#Id
#GenericGenerator(name = "generator", strategy = "guid", parameters = {})
#GeneratedValue(generator = "generator")
#Column(name="TERM_ID")
private String termId;
}
I have a situation where an XML representation of the Entity (and child entities) will be coming in through a web service to update/replace existing ones. My thought was to just delete the old ones and re-create it from the incoming XML.
However, doing a persist when my entities having existing IDs seem to make Hibernate very angry. So is this actually possible or is it better to avoid deleting them and just trying to do it with merge?
Angriness from hibernate:
org.hibernate.PersistentObjectException: detached entity passed to persist: com.idbs.omics.catalog.entity.Term
Thanks
My thought was to just delete the old ones and re-create it from the incoming XML. However, doing a persist when my entities having existing IDs seem to make Hibernate very angry..
Indeed, you cannot assign an Id when it is supposed to be generated, at least not with Hibernate that won't consider the entity as new but as detached (the JPA specification is a bit blurry on the exact rules in this case but that's how Hibernate behaves, see 5.1.4.5. Assigned identifiers for more hints).
So is this actually possible or is it better to avoid deleting them and just trying to do it with merge?
To make the delete/insert possible for the web service use case, you'd have to either:
not assign the id ~or~
use a special version of the entity without a generated identifier ~or~
use bulk operations(?)
The alternative if you're actually updating detached entities would be indeed to use a merge (but have a look at these previous questions just in case).
Which approach is better? I don't know, it think it depends on your needs. The later seems more natural if you're updating existing entities. With the former, you'd really get "new" entities (including a new value for the optimistic locking column). Depending on the exact implementation of the process, performances might also vary. And, by the way, what about concurrency (just to mention it, I'm not really expecting an answer)?
You can use EntityManager.merge to save an updated version of the entity. Be aware that this returns another object than the one you pass to it, because it basically fetches the entity from the database, updates the persistent properties from the object you pass and saves the persistent object.
See http://blog.xebia.com/2009/03/23/jpa-implementation-patterns-saving-detached-entities/ for more information on this problem.