This question is similar to Pete_Gore's but for spring hibernate. I want to create an Entity with an Embedded object which the Embedded object can be nullable, but if it is defined then the properties in the Embedded object should be non-nullable.
Entity.java
#Entity
public class EntityObject {
#Column
private String name;
#Embedded
private EmbeddedObject embeddedObject;// This should be nullable
//Getters, setters, and constructor
}
Embedded.java
#Embeddable
public class EmbeddedObject {
#Column(nullable = false)
private String exampleProperty;// This should be non-nullable
//Getters, setters, and constructor
}
This scenario works when exampleProperty is nullable but when I set it to be non-nullable I get an error similar to the following when creating an EntityObject with a null EmbeddedObject.
NULL not allowed for column "exampleProperty"; SQL statement:
Add in your embeddable class:
#Formula("0")
int aNUll;
The way I achieved this is by separating the Embeddable class into its own table. This is done by declaring a #SecondaryTable on the main Entity class. And then each field of the Embedded class must specify that it uses that table. So your example would be something like this:
Entity:
#Entity
#SecondaryTable(name = "embedded_table", pkJoinColumns = #PrimaryKeyJoinColumn(name = "entity_name"))
public class EntityObject {
#Column
private String name;
#Embedded
private EmbeddedObject embeddedObject; // this is nullable
//Getters, setters, and constructor
}
Embedded:
#Embeddable
public class EmbeddedObject {
#Column(nullable = false, table = "embedded_table")
private String exampleProperty; // this is not nullable
//Getters, setters, and constructor
}
In general, the idea is that Embedded/Embeddable are trying to merge multiple classes into a single database table. Whereas SecondaryTable instructs JPA to split what would otherwise be a single table, into two. As a single table, any entity row would require values for all non-null fields, even ones for the embedded type. As separate tables, the relational semantics permit that no embedded table row exist for an entity row where the embedded object is null. But, if the embeded object is present, a corresponding row will be added to the embedded table, at which point all non-null values must be defined.
I got some inspiration for this from here: https://www.baeldung.com/jpa-mapping-single-entity-to-multiple-tables
Related
I am trying to generate JPA classes for legacy RDMS project.
There is an entity class Person, written in JPA.
The entity Person has another Embeddale class called Address.
I can use set, list or map mapping for Embeddable Address. With any of these there can be multiple embedded objects in Person.
But the requirement is - there can be at most only one instance of embeddable object. How to achieve this requirement? I cannot use subclass entities, it has to be embeddable object only.
You can use single value association something like below
#Entity
public class Person {
#Id
private Long id;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "address_id")
private Address address;
}
#Embeddable
public class Address {
private String street;
private String city;
}
You can read more about #oneToOne here
Using #Embedded annotation the columns of #Embeddable class will be mapped to parent entity's table and hence will have only one instance.
I am building a (spring boot) rest service and I seem to have some fundamental misunderstanding of Hibernate and foreign keys or whatever.
I have two entities:
#Entity
public class ClassA {
#Id
#Column(name = "id", nullable = false)
private Integer id;
#ManyToOne
#JoinColumn(name = "class_b", nullable = false)
private ClassB classB;
// more properties and getters/setters left out for brevity
}
#Entity
#Table(name = "class_b")
public class ClassB {
#Id
#Column(name = "id", nullable = false)
private Integer id;
#Column(name = "name", nullable = false, length = 100)
private String name;
// more properties and getters/setters left out for brevity
}
ClassA has a foreign key to ClassB. I want my user to be able to give me an instance of classA, e.g.
{ //instance of class A, e.g. via POST
id: 19,
class_b_id: 17
}
That means, I get an id for class A and the id from class B. If I wanted to create an entity of class A and save it in the database I have to retrieve the corresponding instance of class B first, call setClassB(...) and then save the instance to the database.
And my entity might even have more foreign keys to more entities which I have to retrieve first, including their properties etc. just to save my new entity.
Is that the way it is supposed to be? Or do I miss something here? Is there a way to define the entity in a way that I can use the foreign keys the way I get them? (And I don't mean: "Don't use hibernate") Without retrieving other objects first?
It just feels wrong and unnessecary.
Why not just create a bidirectional relationship between those entities and use classB to cascade the creation of classA? This way you get the creation/update at once and don't have to retrieve and set the relations manually.
As in your example, you get the id of classA to be created but also class_b_id that you can use to fetch classB instance and proceed with classA creation, that will be attached to classB.
This must be quite naive but I have a doubt on when to use #Entity and #Embeddable.
Say I have a User and Notification class.
#Entity
public class User{
//other properties
#onetomany
private List<Notification> notifications;
}
#Entity
public class Notification{
//properties
}
I understand that there will be tables for class User and Notification, and a third table for mapping.
What if I do it like this?
#Entity
public class User {
//other properties
#ElementCollection
private List<Notification> notifications;
}
#Embeddable
public class Notification{
//properties
}
I know this won't create a table for Notification. But I can still store my notification objects. I went through the documentation, but couple of doubts:
Is it based on whether I want to see class B as a seperate table?
Is there a performance difference b/w creating a table and an embeddable object?
What can I not do with embeddable object that I can do with a table other than directly querying the table?
NOTES
For anyone reading this question, this question too might help you.
Is it based on whether I want to see class B as a separate table?
Yes, when you use #Embedded, You embed that #Embeddable entity in #Entity class, which makes it to add columns for embedded entity in same table of #Entity class.
Is there a performance difference b/w creating a table and an embeddable object?
When you use #Embedded, for table creation, one query is required, also for inserting and selecting a row. But if you don't use it, multiple queries are required, hence, use of #Embedded yields more performance, we can say.
What can I not do with embeddable object that I can do with a table other than directly querying the table?
Removing the respective embedded entity may be, but there may be integrity constraint violations for this.
In JPA, there’s a couple ways to create composite key fields. Lets see the method using the #Embeddable annotation.
Let’s start with the Entity class.
#Entity
#Table
public class TraceRecord {
#Id
private TraceRecordPk id;
#Version
#Transient
private int version;
#Column(columnDefinition = "char")
private String durationOfCall;
#Column(columnDefinition = "char")
private String digitsDialed;
#Column(columnDefinition = "char")
private String prefixCalled;
#Column(columnDefinition = "char")
private String areaCodeCalled;
#Column(columnDefinition = "char")
private String numberCalled;
}
This is a pretty simple Entity class with an #Id and #Version field and a few #Column definitions. Without going into too much detail, you’ll see that the #Version field is also annotated #Transient. I’ve done this simply because my table also doesn’t have a column for tracking versions, but my database is journaled, so I’m not too concerned about versioning. You’ll also notice that the #Column fields have a value of “char” set on the columnDefinition attribute. This is because the fields in my table are defined as char and not varchar. If they were varchar, I wouldn’t need to do this since a String maps to a varchar field by default.
The #Id field is what I’m interested in right now. It’s not a standard Java type, but a class I’ve defined myself. Here is that class.
#Embeddable
public class TraceRecordPk implements Serializable {
private static final long serialVersionUID = 1L;
#Temporal(TemporalType.DATE)
#Column
private Date dateOfCall;
#Column(columnDefinition="char")
private String timeOfCall;
#Column(columnDefinition="char")
private String callingParty;
/**
* Constructor that takes values for all 3 members.
*
* #param dateOfCall Date the call was made
* #param timeOfCall Time the call was made
* #param callingParty Extension from which the call originated
*/
public TraceRecordPk(Date dateOfCall, String timeOfCall, String callingParty) {
this.dateOfCall = dateOfCall;
this.timeOfCall = timeOfCall;
this.callingParty = callingParty;
}
}
To make this class capable of being an #Id field on an Entity class, it needs to be annotated with #Embeddable like I mentioned earlier. The 3 fields I’ve selected for my composite key are just normal #Column definitions. Rather than create getters/setters for each field, I’ve simply implemented a constructor that takes values for all 3 fields, making any instance immutable. When annotating a class with #Embeddable, that class will need to implement Serializable. So I’ve added a default serialVersionUID to accomodate.
Now that you have a class created and annotated with #Embeddable, you can now use it as the type for an #Id field in your Entity class. Simple stuff eh.
I am using Hibernate and JPA. If I have two simple entities:
#Entity
#Table(name = "container")
public class Container {
#Id
#Column(name="guid")
private String guid;
}
#Entity
#Table(name="item")
public class Item {
#Id
#Column(name="guid")
private String guid;
#Column(name="container_guid")
private String containerGuid;
}
and I want to insure that inserting an Item fails if the referenced Container does not exist. I would prefer not to have a Container object populated inside the item object (ManyToOne), how would I do this if it is possible to do?
You can declare arbitrary constraint using columnDefinition attribute:
#Column(name="container_guid",
columnDefinition = "VARCHAR(255) REFERENCES container(guid)")
private String containerGuid;
Note, however, that Hibernate doesn't know anything about this constraint, so that, for example, it may not perform inserts in proper order with respect of it and so on.
Therefore it would be better to create a #ManyToOne relationship. If you are afraid of extra SQL query for Container needed to set this property, you can use Session.load()/EntityManager.getReference() to get a proxy without issuing actulal query.
Try using below relationship mapping
RelationShip Mapping
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#ManyToOne()
#ManyToMany()
<>
#JoinColumn(name="<>")
I have two tables:
1) Application(int appid, int statusid, String appname, String appcity with getter and Setter methods)
2) App_Status(int statusid,String statusDescription with setter and getter methods)
I want to map Application table with App_Status so that I don't have to query separately App_Status table in order to get the statusDescription. One thing I have to careful is that no matter what (Insert,update or delete) to the Application table the App_Status table should be unaffected means its a read only table which is maintained by the DBA internally and used only for lookup table.
I am using JPA annotations so please suggest how to handle this.
The following should work. Map an AppStatus entity on the App_Status table:
#Entity
public class AppStatus {
#Id
private Long id;
private String statusDescription;
// getters, setters, hashCode, equals...
}
And declare it with a one-to-one association in the Application entity:
#Entity
public class Application {
#Id
private Long id;
private String appName;
private String appCity;
#OneToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "statusid", nullable = false, insertable = false, updatable = false)
private AppStatus appStatus;
// getters, setters, hashCode, equals...
}
Pay a special attention to the following details:
I defined the fetch mode to EAGER (note that EAGER is the default if you don't define it) so that the AppStatus will be eagerly fetched when loading an Application.
I didn't define any cascading option so that no operation will be cascaded from Application to AppStatus.
to retrieve all Application, use a FETCH JOIN
FROM Application a JOIN FETCH a.appStatus