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
Related
I got error:
org.hibernate.AnnotationException: #OneToOne or #ManyToOne on xxx.yyy.zz.myentity.xxx_id references an unknown entity: java.util.UUID
code
#ManyToOne
#JoinColumn(name = "xxx_id", nullable = false, updatable = false, referencedColumnName = "xxx_id", insertable
= false)
private UUID xxxId;
I got this when i change from AnotherEntity to UUID. I did this because i dont want to hold an object in my entity but only key to it(key type in AnotherEntity is UUID). I found that this error is cause when Object isnt annotated with
#Entity annotation. Is it true? How can i fix this?
You can represent an Entity as a SQL table and fields (properties) from this Entity as the columns from this table.
That's the easiest way to use Hibernate (or any other JPA implementation).
When you define a relationship (OneToOne, OneToMany, ManyToOne or ManyToMany) you are linking SQL tables so, with JPA, you are linking Entities.
As you can imagine, you can't define a relationship between a table and a column.
So:
your xxxId is supposed to be an object (Entity/Table) mapped in your database and Hibernate must know the column mapping.
that's the purpose of the #Entity annotation and all #Column, #JoinColumn you can use on an Entity class.
so yes, you can't use an object in a ManyToOne relationship that is not annotated with #Entity (it would be considerate by Hibernate like a column)
therefore, you cannot use an object from the JDK (because they are not annotated with any JPA annotation)
more specifically, java.util.UUID is not a class you can change. so you have no way to tell hibernate how it can map it to a Table in your DB.
so the only way I can imagine in your case is to use an entity you created to wrappe the UUID. For example:
#Entity
#Table(name="UUID")
public class UUIDWrapperEntity {
#Id
#Column(name = "UUID")
private UUID uuid;
}
I am trying to have separate auto incremented id generator for each of my entities.
The target database is a SQL Server database, and I am using Hibernate 5.2.4.Final. Also I am generating the tables from code.
I have an abstract BaseEntity and other child entities like below, and thus, I am aiming for TABLE_PER_CLASS.
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity {
protected long id;
#Id
#GeneratedValue(strategy = GenerationType.XXX)
#Column(name = "Id")
public long getId() {
return id;
}
}
#Entity
#Table(name = "Tags")
public class Tag extends BaseEntity {
}
Below are the different scenarios that I have faced so far:
setting XXX to AUTO: Creates a hibernate_sequence table in database, which I assume, will not provide separate id sequence for separate table.
setting XXX to SEQUENCE: Same as above. Referred this, while doing it.
setting XXX to TABLE: Creates a hibernate_sequences table, which can provide separate id sequence for separate table. However, I have found out that this is quite expensive (same reference as above), and also not my preferred strategy.
setting XXX to TABLE: Does not work for TABLE_PER_CLASS.
What I actually want to use is the native identity column of SQL Server. However, using the SEQUENCE is also an option, but I am not sure how to create and use one for each table from hibernate. Please suggest how either one of these two can be achieved.
Update on the answer by Khalil M. I tried it in 2 possible ways:
applying on BaseEntity -> does not create a separate sequence for each table, and rather creates a ID_SEQNCE, which queried before saving every new entity. So, I am not sure how this is any different than using GenerationType.TABLE.
applying it on each individual entity class -> while saving, the generator creates duplicate id.
for creating a sequence use this
#Id
#GeneratedValue(generator = "ID_SEQ", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "ID_SEQ", sequenceName = "ID_SEQNCE",allocationSize=1)
Edit:
You have to make it by yourself because what you are asking is not supported in Table per class
the id has to be shared across several tables. Consequently, when
using this strategy, you should not use AUTO nor IDENTITY.
for more info
Use strategy = GenerationType.IDENTITY
A short example is below
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
The GenerationType.IDENTITY is the easiest to use but not the best one from a performance point of view. It relies on an auto-incremented database column and lets the database generate a new value with each insert operation. From a database point of view, this is very efficient because the auto-increment columns are highly optimized, and it doesn’t require any additional statements.
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.
Could somebody help me in setting appropriate annotation in hibernate for following case:
I have three tables:
Account, Card and AccountCard.
AccountCard is joining table for OneToMany relationship between Card and Account (account has many cards, card is attached to only one account).
I need to add to Account a List cards property and to Card model Account account property. This is the easy thing.
The problem is that I get "Cannot insert null value to AccountCard.id" while persisting Account with Cards.
Also I need to use sequence to generate IDs for joining table but don't know how.
Any help would be very appreciated.
Here is the code in Card:
#ManyToOne(fetch = FetchType.LAZY)
#JoinTable(name = "account_card", joinColumns = #JoinColumn(name = "crd_id"), inverseJoinColumns = #JoinColumn(name = "acc_id"))
private Account account;
I don't want to have a mapping in Account class so List cards is not added.
In your #JoinTable annotation, I see reference to an account_name table and not AccountCard. Is there actually an AccountCard table somewhere?
A join table usually doesn't need an id key of its own, and if you have hibernate autogenerate your table DDL it won't include one.
If you do indeed need an id on the join table, I don't think there's a way or a need to make hibernate aware of it, but you should make the column NOT NULL AUTO_INCREMENT in your SQL DDL.
Did you try to generate the tables first in the database (in my case mysql) and then create the entity with an ide like nebans? An auto increment id column in mysql then ends with:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID")
private Integer id;
Check out http://netbeans.org/kb/docs/javaee/ecommerce/entity-session.html for a sample how to use netbeans to create entities from database
I am having trouble working out how to do a bulk delete of a Person object using JPA, when the Person objects contain data stored using an #ElementCollection. Any ideas on how to do this would be much appreciated.
#Entity
#Table(name="at_person")
public class Person implements Comparable<Person> {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private long id = 0;
#Column(name="name", nullable = true, length = 128)
private String name = "";
#ElementCollection
#Column(name = "email")
#CollectionTable(name = "person_email", joinColumns = #JoinColumn(name = "person_id"))
private Set<String> email = new HashSet<String>();
}
What I am doing at the moment is this, and it fails with a foreign key constraint error:
Query query=em.createQuery("DELETE FROM Person");
Caused by: java.sql.SQLException: integrity constraint violation:
foreign key no action; FKCEC6E942485388AB table: PERSON_EMAIL
If it can be a pure JPA annotation rather than a Hibernate annotation that would be a bonus!
I'll let you interpret the part of the JPA 2.0 specification that mentions that a bulk delete operation is not cascaded:
4.10 Bulk Update and Delete Operations
...
A delete operation only applies to
entities of the specified class and
its subclasses. It does not cascade to
related entities.
And the fact is that Hibernate won't cascade a delete to a collection table either. This has been reported in HHH-5529 and the suggested approaches are:
You could also (a) clean up the collection table yourself or (b) use cascading foreign keys in the schema.
In other words, (a) use native SQL or (b) use a cascade delete constraint at the database level - and you'll have to add it manually, I don't think you can use #OnDelete with the #ElementCollection annotation (same story as HHH-4301 IMO).