In this article http://www.jroller.com/eyallupu/entry/hibernate_the_any_annotation and also in this question How to use Hibernate #Any-related annotations?, how #Any annotation can be used was explained. But how can I get borrows for each DVD/VHS/BOOK? How can I do mapping definition on DVD/VHS/BOOK?
I don't think this is supported and, as mentioned in the documentation:
2.4.5.2. #Any
The #Any annotation defines a
polymorphic association to classes
from multiple tables. This type of
mapping always requires more than one
column. The first column holds the
type of the associated entity. The
remaining columns hold the identifier.
It is impossible to specify a foreign
key constraint for this kind of
association, so this is most certainly
not meant as the usual way of mapping
(polymorphic) associations. You should
use this only in very special cases
(eg. audit logs, user session data,
etc).
While I understand that this annotation has been introduced to map an association property to different types of entities that don't have a common ancestor entity, I think it would be better to introduce a base type the other entities would inherit from for bidirectional relations.
See also
#Any bidirectional relationship fails
Yes, the problem with bi-directional associations where one side is polymorphic (mapped with #Any or #ManyToAny), is that Hibernate auto-generates an invalid foreign key. Personally, I view this as a bug, not a usage error.
You can get around this by specifying the foreign key explicitly, i.e. not rely on Hibernate to infer it. In the Borrow <--> DVD/VHS/Book example, let's say you want a bi-directional, many-to-one association between Borrow and DVD/VHS/Book (the "item"), then you map it on the Borrow side with the polymorphic #Any mechanism to item, and on the item side with a #OneToMany to Borrow.
BUT: on the latter property/getter, you also specify, explicitly, the join column to use, e.g. "ITEM_ID". That should force Hibernate to use only "ITEM_ID", and not (as I've seen) ITEM_ID + ITEM_TYPE that it infers by default from the #Any definition on the other side.
If you don't have a "Item" superclass for DVD/VHS/Book, you'll have to declare this in each class, something like:
#Entity
class Book {
...
#OneToMany
#JoinColumn(name="item_id")
public List<Borrow> getBorrows() {
return this.borrows;
}
}
Related
According to the Hibernate docs, MappedSuperclass allows mapping inheritance, where the super class is not treated as an entity, and where polymorphic queries that fetch objects by the base class are not supported.
On the other hand, the table per class strategy is similar in terms of the generated schema in the DB, except that it maps the super class to a table if it is not an abstract. However it supports polymorphic queries.
My question is: why would anyone use the #MappedSuperclass strategy? Is there a performance issue implied if the parent class is treated as an entity? Any ideas around this is appreciated.
#MappedSuperclass
By default, properties of the superclass are ignored and not persistent!
You have to annotate the superclass with #MappedSuperclass to enable embedding of its properties in the concrete subclass tables.
You can override column mappings from the superclass in a subclass with the #AttributeOverride annotation or several with #AttributeOverrides.
You could declare the identifier property in the superclass, with a shared column name and generator strategy for all subclasses, so you wouldn’t have to repeat it. But it’s optional!
The main problem with implicit inheritance mapping is that it doesn’t support polymorphic associations very well. In the database, you usually represent associations as foreign key relationships. If the subclasses are all mapped to different tables, a polymorphic association to their superclass can’t be represented as a simple foreign key relationship.
Polymorphic queries that return instances of all classes that match the interface of the queried class are also problematic. Hibernate must execute a query against the superclass as several SQL SELECTs, one for each concrete subclass.
A further conceptual problem with this mapping strategy is that several different columns, of different tables, share exactly the same semantics. This makes schema evolution more complex. For example, renaming or changing the type of a superclass property results in changes to multiple columns in multiple tables. Many of the standard refactoring operations offered by your IDE would require manual adjustments, because the automatic procedures usually don’t account for things like #AttributeOverrides. It also makes it much more difficult to implement database integrity constraints that apply to all subclasses.
So, this approach is a good chose for the top level of your class hierarchy,
where polymorphism isn’t usually required, and when modification of the superclass
in the future is unlikely.
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
The database identifier and its mapping have to be present in the superclass, to share it in all subclasses and their tables. This is no longer optional, as it was for the #MappedSuperclass mapping strategy.
Note that the JPA standard specifies that TABLE_PER_CLASS is optional, so not all JPA implementations may support it. The implementation is also vendor dependent — in Hibernate, it’s equivalent to a <union-subclass> mapping in the old native Hibernate XML metadata.
The advantages of this mapping strategy are clearer if we examine polymorphic queries. The tables are combined with a UNION operator, and a literal is inserted into the intermediate result; Hibernate reads this to instantiate the correct class given the data from a particular row. A union requires that the queries that are combined project over the same columns; hence, you have to pad and fill nonexistent columns with NULL. You may ask whether this query will really perform better than two separate statements. Here you can let the database optimizer find the best execution plan to combine rows from several tables, instead of merging two result sets in memory as Hibernate’s polymorphic loader engine would do.
Another much more important advantage is the ability to handle polymorphic associations. Hibernate can use a UNION query to simulate a single table as the target of the association mapping.
So, this approach is a good chose when you need to use polymorphic queries and associations.
P.S. This is almost verbatim quotation from the excellent book: Java Persistence with Hibernate (Bauer, King, Gregory)
meaning a class whose mapping information is applied to the entities that inherit it.
Reading a wiki page about Hibernate I elaborated some perplexing conclusions:
1) Bidirectionality is reccomended in one-to-many
2) Bidirectionality is optional in many-to-one
3) Bidirectionality is normally present in many-to-many
4) Unidirectionality is reccomended in one-to-one relationships,
using as owner class the one with the primary key of the
relation (not the foreign key).
Are these statements true? Do you have any example to explain why in some cases unidirectionality is reccomended and in others bidirectionality is reccomended instead?
Here's the wiki page (read under "concepts"):
http://wiki.elvanor.net/index.php/Hibernate
Note that "bidirectionality" in the context of Hibernate means that in your Java classes, both sides of the relationship maintain a link to the other side. It has no impact on the underlying database schema (except in the case of indexed collections, see below), it's just whether or not you want the Java side to reflect that.
For all of your conclusions, "recommended" actually translates to "it usually ends up making sense, given your business logic, that you'd do it this way".
You really want to read through chapters 7 and 8 of the Hibernate Core Reference Manual.
It's recommended if you need it. A lot of convenience comes from specifying a bidirectional relationship; particularly it becomes possible to navigate the relationship from both ends in your business logic. However, if you don't actually need to do this, there's nothing to gain. Use whatever is most appropriate for the situation. In practice I've found that I want to specify both ends of the relationship to Hibernate more often than not -- but it is not a rule, rather, it reflects what I want to accomplish.
This is true. In a many-to-one (or one-to-many) relationship, it is optional. Consider the following schema:
table: users
fields: userId, userName
table: forumPosts
fields: postId, userId, content
Where forumPosts.userId is a foreign key into users. Your DAO classes might be (getters/setters omitted for brevity):
public class User {
private long userId;
private String userName;
}
public class ForumPost {
private long postId;
private User user;
private String content;
}
As you can see, this is a unidirectional many-to-one relationship (ForumPost-to-User). The ForumPost links to the user, but the User does not contain a list of ForumPosts.
You could then add a one-to-many mapping to User to make it have a list of ForumPosts. If you use a non-indexed collection like a set, this has no impact on the database schema. Merely by specifying both sides to Hibernate, you have made it bidirectional (using exactly the same schema as above), e.g.:
public class User {
private long userId;
private String userName;
private Set<ForumPost> forumPosts;
}
public class ForumPost {
private long postId;
private User user;
private String content;
}
Hibernate will now populate User.forumPosts when necessary (essentially with SELECT * FROM forumPosts WHERE userId = ?). The only difference between bidirectional and unidirectional here is that in one case Hibernate fills a set of ForumPosts in User, and in the other case it doesn't. If you ever have to get a collection of any given user's posts, you will want to use a bidirectional relationship like this rather than explicitly constructing an HQL query. Depending on your inverse/insert/update/cascade options in your relationship, you can also add and remove posts by modifying the User's set of posts, which may be a more accurate reflection of your business logic (or not!).
The reason I specified that non-indexed collections don't impact the underlying schema is because if you want to use an ordered, indexed collection like a list, you do have to add an extra list index field to the forumPosts table (although you do not have to add it to the ForumPost DAO class).
This is true, but is not a requirement and it's deeper than that. Same as above. Bidirectionality is usually present in many-to-many. Many-to-many relationships are implemented with a third join table. You specify the details of this table on both sides of the relationship. You can simply not specify the relationship on one side, and now it's a unidirectional relationship. Again, whether or not you tell Hibernate about the mapping is what determines if its unidirectional or bidirectional (in the context of Hibernate). In this case it also has no impact on the underlying schema unless you are using an ordered index collection. In fact, the many-to-many example in the Hibernate reference manual is a unidirectional setup.
In reality, it would be odd to have a unidirectional many-to-many relationship, unless perhaps you are working with an existing database schema and your particular application's business logic has no need for one of the sides of the relationship. Usually, though, when you've decided you need a many-to-many relationship, you've decided that because you need to maintain a collection of references on both sides of the relationship, and your DAO classes would reflect that need.
So the correct conclusion here is not merely that "bidirectionality is normally present in many-to-many", but instead "if you've designed a database with a join table, but your business logic only uses a unidirectional relationship, you should question whether or not your schema is appropriate for your application (and it very well may be)".
This is not true. Exactly the same as all the points above. If you need to navigate the one-to-one relationship from both sides, then you'd want to make it bidirectional (specify both sides of the mapping to Hibernate). If not, then you make it unidirectional (don't specify both sides of the mapping to Hibernate). This again comes down to what makes sense in your business layer.
I hope that helps. I left a lot of intricacies out. You really should read through the Hibernate documentation - it is not organized particularly well but Chapter 7 and 8 will tell you everything you need to know about collection mapping.
When I'm designing an application and a database from scratch, personally, I try to forget about Hibernate and the database entirely. I set up my DAOs in a way that makes sense for my business requirements, design a database schema to match, then set up the Hibernate mappings, making any final tweaks to the schema (e.g. adding index fields for ordered collections) at that point if necessary.
I have two entities with a many-to-one relationship between them. Many B entities are related to an A entity. My B table has an A_ID column. In some situations, we may have a B entity that has an A_ID but doesn't relate to any row in A. I know this isn't ideal but it's part of the old system and we can't really touch this portion of the code.
With proper Hibernate entities, I'm able to add B entities when we have an A entity to associate with using B's setA() method and B's getAs().add() method. I don't see any way to deal with the case where I'd like to add a B entity that isn't associated with an A entity (B's A_ID = 10, for example, where there's no A with an ID = 10). Is this possible or am I stuck breaking our entity hierarchy at this point and dealing with it manually?
Is there some way to add a setAId() to the B entity and either use that or the setA() method but not both? Will Hibernate allow this? When I try to add the getter and setter on B, I get the following error:
MyHibernateException: Hibernate SessionFactory creation failed, hibernateCfgFileNm=hibernate.xml
...
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: test.B column: A_ID (should be mapped with insert="false" update="false")
Sorry for not providing code. I think this explanation is sufficient but if code is required, I can add it.
With my understanding of entity relations (I assume you're mapping these with standard JPA #ManyToOne / #OneToMany relations?) I believe you're going to run into some fun issues here.
I would create my A entities using a sequence generated ID, and allow for 'placeholder' A entities which do nothing but carry the A_ID from the old system. Just make your code aware that not every A entity will be a full entity (it may just place-hold those A_IDs you mentioned above) and gracefully handle it, allowing you to always provide an A entity, with an ID decoupled from the legacy system.
I don't think you'll be able to map the relation to the same column and set a value in the column without the relation causing issues -- unless perhaps if you mark the relation as LAZY fetch and catch the exceptions which are bound to occur when it tries to resolve the non-existent Entity A. That may also work -- in that case, try to map the relationship column as read-only (insert="false" update="false"), and do everything with the setAId(id). You may need to have your setA(A) method only operate on IDs rather than managed collections, since reading a collection will by it's very nature fetch any related rows.
Your best bet is to decouple from the IDs of the legacy system if the semantics of the legacy IDs loosely translate to 'here, this ID may be a null object.'
I use JPA 2 with Hibernate. There are two entity classes, CardElement and IdentityDocumentKind. The last one is an inherited entity of the first one. SINGLE_TABLE inheritance strategy is used. When I try to select an instance of the parent class by query from CardElement where id = '123456' the following error occures:
Object with id: 123456 was not of the specified subclass:
org.cp.cardsystem.CardElement (Discriminator: SDocClass)
I don't have a subclass for "SDocClass" discriminator value. Actually at the moment of developing IdentityDocumentKind class querying of CardElement was used widely across the application. So I can't create a subclass of CardElement for each discriminator value and replace CardElement with it in all existent queries. It would be cost too much efforts for me. Is there a way to instantiate parent entity class when SINGLE_TABLE inheritance strategy is used?
I am not sure if I understand your problem correctly. You are using Single Table strategy to store the whole inheritance hierarchy. However, you have only mapped some of the discriminators, and this time, it is the unmapped discriminator causing the problem (because Hibernate dunno what that subclass means). Am I understanding your problem correctly?
Consider work against a special DB view instead of the real table. That view expose only records with discriminator you can handle.
Problem is solved. I've annotated root entity class of inheritance hierarchy (CardElement) in this way: #DiscriminatorValue(value = "not null"). Now I can select objects of this class without creating subclass for each discriminator value. not null and null seem to be Hibernate's special discriminator values which match in discriminator column anything except null and null respectively. I've not found any information about these values in Hibernate's official documentation. So it could be some kind of undocumented feature.
Put another way: How do you model/map a heavily reused child class/table to many different parent entities?
I have several entity types each being persisted into its own table:
class A --> table A
class B --> table B
....
Now I need to make each of these classes the parent of a 1:M unidirectional child collection. The collection is a history of approvals the entity has gained over time. The Child domain class is called "ApprovalItem". The Approval class is exactly the same for all types of parents.
What is the best way to map this? If I create a single table to hold all ApprovalItems, then I can't enforce a FK relation to the PK of the entity and/or I am left with a bad database design.
On the other hand, I could create an ApprovalIems table for each entity type (e.g. A_ApprovalItems, B_ApprovalItems, etc.). This seems like a good schema on the database side, but then it seems I need to create a separate domain classes in Java for each entity approval (e.g. AAprrovalItem class, BApprovalItem class, etc.). This seems like a lot of hassle and complexity to create so many new classes in Java that do nothing other than allow me to put in different JPA mapping annotations.
Is there a mapping technique in Hibernate that will allow me to have one class in Java map to several different tables depending on who the parent owner of the collection is?
I could create an ApprovalItem table for each entity type (e.g. A_ApprovalItem, B_ApprovalItem, etc.). This seems like a good schema on the database side
But
It seems i need to create a separate domain classes in Java for each entity approval (e.g. AAprrovalItem class, BApprovalItem class, etc.).
You do not need it. you can create a single ApprovalItem class and create a #OneToMany relationship between your parent classes and your ApprovalItem. Hibernate takes care to create a linked table for each relationship.
#Entity
public class ClassA {
#Id
#GeneratedValue
private Integer id;
// Hibernate will create CLASSA_APPROVALITEM to link both class
#OneToMany
private List<ApprovalItem> approvalItemList;
}
#Entity
public class ClassB {
#Id
#GeneratedValue
private Integer id;
// Hibernate will create CLASSB_APPROVALITEM to link both class
#OneToMany
private List<ApprovalItem> approvalItemList;
}
And your ApprovalItem class
#Entity
public class ApprovalItem {
#Id
#GeneratedValue
private Integer id;
// Nothing else
}
But Let's see what Java Persistence with Hibernate book talks about it
You may have shared references to the Bid objects. As suggested earlier, a User may have a collection of references to the Bid instances they made. You can’t delete an item and all its bids without removing these references first. You may get an exception if you try to commit this transaction, because a foreign key constraint may be violated.
So keep it in mind when dealing with shared references.
In order to see how the target schema looks like, you can use the following
AnnotationConfiguration configuration = new AnnotationConfiguration();
configuration
.addAnnotatedClass(ClassA.class)
.addAnnotatedClass(ClassB.class)
.addAnnotatedClass(ApprovalItem.class)
.setProperty(Environment.USER, <TYPE_YOUR_USER>)
.setProperty(Environment.PASS, <TYPE_YOUR_PASSWORD>)
.setProperty(Environment.URL, <TYPE_YOUR_URL>)
.setProperty(Environment.DIALECT, <TYPE_YOUR_DIALECT>)
.setProperty(Environment.DRIVER, <TYPE_YOUR_DRIVER>);
SchemaExport schema = new SchemaExport(configuration);
schema.setOutputFile("schema.sql");
schema.create(<DO_YOU_WANT_TO_PRINT_TO_THE_CONSOLE>, <DO_YOU_WANT_TO_EXPORT_THE_SCRIPT_TO_THE_DATABASE>);
It will generate a file called schema.sql, which contains your target schema
regards,
Chapter 8. Inheritance Mapping of Hibernate Documentation might help.
Otherwise, I see no problem having multiple ApprovalItem derived class that "do nothing", like you say, since it does differentiate the Approval, it's like having a type of approval. Seeing your model like so, I would recommend using multiple classes, even if they only inherit from your base ApprovalItem class.
Have I well understood your question or am I missing something else more subtle?