JPA join to inherited class - java

In jpa I have some entity (Content and Product for now but more can come) that should join to Comment entity.
Problem is I don't want to have extra field(and column in table) in Comment entity for each join entity (Products, Contents..) because these entities will increase in future.
I find one semi-solution is to use single table inheritance and create concrete Comment class like CommentContent, CommentProduct, and use discriminator column but joining to entities (Content and Product) still remain.
what do you suggest?
Edit:
sample relation for example between Comment and Content will be #MayToOne that many Comments belongs to one Content and so for Product..
Edit 2
in pure table relationship schema (without ORM like hibernate/jpa) I can and I do this kind of solution:
add to column in comment table 1-item_type and 2-item_id witch item_type specify other side table name (product, content in my question) and item_id specify foreign key to table that it name is at item_type column
How can I model this in Jpa/hibernate ORM?

You can model what you described with Hibernate like
class Content {
#OneToMany
#JoinColum(name = "item_id")
#Where("item_type = 'CONTENT'")
Set<Comment> comments;
}
class Product {
#OneToMany
#JoinColum(name = "item_id")
#Where("item_type = 'PRODUCT'")
Set<Comment> comments;
}
class Comment {
#Id
#GeneratedValue
Long id;
#Enumerated(STRING)
ItemType itemType;
Lont itemId;
}
enum ItemType {
CONTENT,
PRODUCT
}

You can try #ManyToOne for your upcoming entities. So here you don't need to add new columns in Comment entity(base table) Check this example : https://howtoprogramwithjava.com/hibernate-manytoone-unidirectional-tutorial/

What type or relation is this?
If it is #OneToOne you can put information about relation with Comment in Product and Content, and in Comment use option MappedBy to map them, you will skip the extra columns in Comment.
If it is #OneToMany you won't make any column in Comment but rather again put information in Product and Content and only use mappedBy on collection of this objects on the Comment site.
CheckForMoreInfo

Related

Storing data using hibernate for inter related tables

I have two tables (say table A and table B). Table B has foreign key from table A primary key. I generated my java entities using netbeans IDE and i now have something like:
For table A:
#Entity
#Table(name = "WORKFLOW_TRANSACTION")
public class WorkflowTransaction implements {
#OneToMany(mappedBy = "wtId")
private Collection<WorkflowTask> workflowTaskCollection;
#Id
#Basic(optional = false)
#NotNull
#Column(name = "APP_ID")
private BigDecimal appId;
.
.
.
For table B:
#Entity
#Table(name = "WORKFLOW_TASK")
public class WorkflowTask implements Serializable {
#JoinColumn(name = "WT_ID", referencedColumnName = "APP_ID")
#ManyToOne
private WorkflowTransaction wtId;
#Id
#Basic(optional = false)
#NotNull
#Column(name = "TASK_ID")
private BigDecimal taskId;
#Column(name = "STEP_NUM")
private BigInteger stepNum;
.
.
.
Now my questions are:
What is the correct way to save data, should I create object for table B entity and set it in table A entity and then save table A?
I am generating entity beans using netbeans IDE feature. Are there any known disadvantages of it?, if yes, what?
You have bi-directional association, so you need to setTable B property in Table A entity class and also vice-versa. Since you have not declared cascading, you need to save the Table A entity first and then Table B entity.
Alternatively, if you save Table B and then Table A entity classes, the hibernate generates an extra SQL update command to maintain the relationship.
But if you want hibernate to save Table B entity when you save Table A entity then you need to add Cascade property:
#OneToMany(mappedBy = "wtId", cascade=CascadeType.ALL)
I don't think you will have any disadvantages if you use Netbeans for generating the entity classes, it save you time in writing the entities. But if you want to learn then writing entities without Netbeans is good.
To achieve this you can use two type of techniques XML mapping or Annotations
In both these techniques the common point is use
cascade="save-update"
What happens is that you set an attribute in one table getter and it will automatically insert into the many relation when inserting into one relation table

Prevent duplicate entry for unique constraint

I am trying to save tags which are related to an article in my MySQL database. The relation between those two columns is 1:N. Each item has an auto generated key. The name of a tag is unique.
If I insert a new article with an existing tag, I get a duplicate entry exception for the unique constraint (MySQLIntegrityConstraintViolationException). This are my two entities:
Article.java
#Entity
public class Article implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany(cascade = CascadeType.ALL)
#JoinTable
private Set<Tag> tags = new HashSet<Tag>();
/* getter and setter */
}
Tag.java
#Entity
public class Tag implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(unique = true)
private String name;
/* getter and setter */
}
Hibernate generate following tables: article, tag, article_tag. For the first article the records are correct.
I use following code to insert a new article (only for testing):
Article article = new Article();
Tag tag = new Tag();
/* set the values */
EntityManager em = EMF.getInstance().get();
em.getTransaction().begin();
em.merge(article);
em.getTransaction().commit();
How could I get JPA to use the existing tag for the article instead of create a new one. How do I set the relation between those so components correctly?
In general the relationship between articles and tags is a many-to-many relationship as an article may have many tags and each of these tags may be reused in many articles.
To indicate a many-to-many relationship the #ManyToMany annotation is required.
Also to make something clear, in the OP it is indicated a unidirectionaly one-to-many relationship as the #JoinTable annotation has been used on the many side. This is the reason a join table has been created. In addition as a consequence if a #ManyToOne annotation is used in Tag class the many-to-one will be another unidirectional relationship. Just be careful there as they will be handled as two independent unidirectional relationship with probable strange behaviour and any configuration will not affect both entities, since it is not a biderictional relationship.
Finally, if it is required to have a one-to-many unidirectional relationship but also reuse the tags, it is required to retrieve them based on their name, so that they have the correct record id and then set the to the Article instance. If you try to set a new instance of Tag which will have no record id but a name that already exists, then the jpa provider will try to insert the new tag and a unique constraint exception will be thrown, because of the duplicate tag name. Also will need to remove any unique constraint referred to tag_id in article_tag table.

JPA 2: how to declare primary-key columns in #ElementCollection tables

in JPA2 when we are using Embed-able (Basic Type like String.. etc ) object in Entity using with #ElementCollection and #CollectionTable annotation , the new table is created , but in new table how to declare primary-key contraint in column ? following is my code
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
private String salary;
#Transient
private String phnNum;
#Enumerated(EnumType.STRING)
private EmployeeType type;
#ElementCollection
#CollectionTable(name="vacations" , joinColumns=#JoinColumn(name="Emp_Id"))
private Collection<Vacation> vacationBooking;
#ElementCollection
private Set<String> nickNames;
...................
with this code the "vacation" and "employee_nickname" two tables are created in schema. but i want to declare the one primary-key column in both table . what i do for this?
It looks like a primary key per se is not supported by JPA 2.0:
From Wikibooks:
The JPA 2.0 specification does not provide a way to define the Id in the Embeddable. However, to delete or update an element of the ElementCollection mapping, some unique key is normally required. Otherwise, on every update the JPA provider would need to delete everything from the CollectionTable for the Entity, and then insert the values back. So, the JPA provider will most likely assume that the combination of all of the fields in the Embeddable are unique, in combination with the foreign key (JoinColumn(s)). This however could be inefficient, or just not feasible if the Embeddable is big, or complex.
Some JPA providers may allow the Id to be specified in the Embeddable, to resolve this issue. Note in this case the Id only needs to be unique for the collection, not the table, as the foreign key is included. Some may also allow the unique option on the CollectionTable to be used for this. Otherwise, if your Embeddable is complex, you may consider making it an Entity and use a OneToMany instead.
Do you mean that you want to assign 'id' from Employee table as foreign key to the Vacation table?
In that case, you should use #OneToMany instead of #ElementCollection

JPA: #OrderColumn and visible state of an entity?

This is a followup question to:
Is #ManyToMany(mappedBy = ... ) + #OrderColumn supported by the JPA?
I'm referring to the #OrderColumn Java docs:
http://docs.oracle.com/javaee/6/api/javax/persistence/OrderColumn.html
The text there is the same as what the JPA 2 spec writes in section 11.1.39 OrderColumn Annotation.
What does the part "the order column is not visible as part of the state of the entity" mean exactly? There's a lot of room for interpretation on that.
Does that mean the order column must not be part of any FKs and/or PKs defined? Or only not in FKs (PK allowed)? What does the state of an entity comprise? AFAIK the JPA spec doesn't define that.
Thanks
The order column is not a field in the Entity class(es), so it isn't visible (as such).
OPENJPA. Please look at this code, it is the best way to understand
//This is in the parent table
#OneToMany(cascade = CascadeType.ALL, mappedBy = "parentTable", fetch = FetchType.EAGER)
#OrderColumn
private ArrayList<child_class_type> childTable = new ArrayList<child_class_type>();
//This is in the child table
#ManyToOne(fetch = FetchType.EAGER, optional = false)
private parentTableClass parentTable;
This will get an ordered list(child table). :)
John V, Col

How to add a separate Primary Key to a Join Table in Hibernate

I have a question about Hibernate ManyToMany mappings. I have two classes A and B and the mapping between them is a ManyToMany mapping resolved by Hibernate:
#Entity
#Table(name="A")
public class A {
#Id
#GeneratedValue
private Long id;
#ManyToMany
#JoinTable(name="C", joinColumns=#JoinColumn(name="a_id"), inverseJoinColumns=#JoinColumn(name="b_id"))
private Set bs;
}
#Entity
#Table(name="B")
public class B {
#Id
#GeneratedValue
private Long id;
#ManyToMany(mappedBy="bs")
private Set bs;
}
As you can see, the Join Table I use is C. The foreign keys to A and B are "a_id" and "b_id". My understanding is, that Hibernate creates a composed Primary Key with a_id and b_id for table C.
I don't want to have an entity C in my model. But instead of a composed primary key on table C, I would like to have a generated ID and a unique constraint on the fields a_id and b_id.
Is it possible to tell Hibernate to use a separate primary key? Without adding an entity C?
I would appreciate any help.
Thanks a lot!
You should do iyt like this. But it can be appled only for list (not for sets)
#Entity
#TableGenerator(name="ids_generator", table="IDS")
public class Passport {
...
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name="PASSPORT_VISASTAMP")
#CollectionId(
columns = #Column(name="COLLECTION_ID"),
type=#Type(type="long"),
generator = "ids_generator"
)
private Collection<Stamp> visaStamp = new ArrayList();
...
}
I don't think it is possible. And I don't see a problem in defining a C entity.
If you have any additional information ind the join-table, it will not be accessible to you, because your Set contains the target entity - A or B.
Also, your Sets would better make use of generics - i.e. Set<A> and Set<B>.
Btw, Hibernate might not be alarmed by the fact that the table creates another entity - using your current mapping might work (disregarding completely the id column). When you said "Hibernate creates", I assumed you are generating your schema from your entity model. Now it seems it's the opposite, so give it a try.
But instead of a composed primary key on table C, I would like to have a generated ID and a unique constraint on the fields a_id and b_id.
Normally the primary key of the JoinTable is made of the combination of both foreign keys. At least, this is what JPA would generate. But if you don't use the JPA provider to generate the model and if the PK can be generated by the database (using an IDENTITY column, a trigger, etc), then you should be able to use the C table for your ManyToMany association (without having to introduce an extra entity and to transform the relation in two OneToMany). Did you actually try?

Categories

Resources