#Entity
public class Blobx {
private String name;
private BlobKey blobKey;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key id;
//getters and setters
}
#Entity
public class Userx {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key id;
private String name;
#OneToMany
private List<Blobx> blobs;
//getters and setters
}
while persiting the above Userx entity object i am encountering
java.lang.IllegalStateException: Field "entities.Userx.blobs" contains a persistable object that isnt persistent, but the field doesnt allow cascade-persist!
I think you need to add a cascade attribute so that the JPA provider can cascade persist on the new Blobx added to the blobs. Currently, the JPA provider can't, as reported by the error message. So change it like this (adapt the CascadeType to match your needs):
#OneToMany(cascade = CascadeType.ALL)
private List<Blobx> blobs;
Related
I have defined the following two classes in hibernate
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
}
#Entity
public class PhoneNumber {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne(cascade = CascadeType.ALL)
private Person person;
}
When I persist a phone number object or a person object it's getting inserted properly.
But when I do
Person person = session.get(Person.class,1);
session.remove(person);
transaction.commit();
I get the foreign key violation exception. But since I have declared a column as ManyToOne shouldn't hibernate automatically delete the corresponding phonnumber records?
I am not sure if I need to add any extra code to do that
You have a bi-directional relationship, that is why you have to add the PhoneNumbers in your Person too. And use the mappedBy attribute to show that the Person is the inverse side and whenever it is deleted, please delete every phone number also.
Like this:
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
#OneToMany(mappedBy="person", cascade = CascadeType.ALL)
private Set<PhoneNumber> phoneNumbers;
}
Check this for more information.
First of all, you have to define the relationship between Person and PhoneNumber in both classes.
The error is thrown because there are phone numbers depending on the person object you removed.
If you add #OneToMany you can define also the property cascade = CascadeType.ALL and then all phone numbers are removed consequently.
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
#OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
private List<PhoneNumber> phoneNumbers;
}
#Entity
public class PhoneNumber {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne
private Person person;
}
I have three Entities i'm modeling and am having issues with the associated annotations. I basically have a class that I intend on returning to the caller, a nested listed of Project's and the Project can contain a nested list of Endpoint's. It's a top-level has-a one-to-many, then the nested one-to-many has two one-to-many's.
I've played with #JoinColumn annotations, i've attempted to put a #ManyToOne on the other side of the OneToMany's (but it doesn't like that it's a Long..). I'm just fairly new and unsure on how to do this. I think the mappedById is the solution, but i'm uncertain.
Main Issue: This code allows me to "save" to the database, but upon retrieval, the list of Project's inside the DownDetectorPackage is empty.
A CascadeType.ALL throws referential integrity errors that I don't completely understand.
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Builder
public class DownDetectorPackage {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany(mappedBy="id",fetch = FetchType.EAGER)
private List<Project> projects;
#Temporal(TemporalType.DATE)
private Date dateJobsLastRan;
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class Project{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String projectName;
#OneToMany(mappedBy="id")
private List<Service> externalDependencies;
#OneToMany(mappedBy="id")
private List<Service> endpoints;
}
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class Service {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String url;
private Boolean endpointIsUp;
private String serviceName;
}
You should be using #JoinColumn instead of mappedBy. MappedBy can be used when you have used #ManyToOne in the other class too, which you haven't.
So your final class should look something like this (this is applicable for the other classes too which you have mentioned) :
public class DownDetectorPackage {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#JoinColumn(name = "downDetectorPackageId")
#OneToMany(fetch = FetchType.EAGER)
private List<Project> projects;
#Temporal(TemporalType.DATE)
private Date dateJobsLastRan;
Also, remember to state the parent object name in #JoinColumn annotation, since it would create a column for that foreign key.
You should mark every join column as JoinColumn denotating the referenced column from the other entity. Then, you are supposed to say which relation type are using this column.
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String projectName;
#JoinColumn(referencedColumnName = "id")
#OneToMany(fetch = FetchType.LAZY)
private ExternalDependencyEntity externalDependencies;
#JoinColumn(referencedColumnName = "id")
#OneToMany(fetch = FetchType.LAZY)
private EndpointEntity endpoints;
}
Finally, note that in a relational database, every fk column can takes only 1 value (pk of referenced entity id), so, on your entity, you should mark the data type as the entity you are refering to and no as a collection.
I think this sould solve your problem.
#Entity
public class TestPair implements Serializable {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
#OneToOne(cascade = {CascadeType.ALL})
#JsonProperty("target_Test")
private Test targetTest;
#OneToOne(cascade = {CascadeType.ALL})
#JsonProperty("source_Test")
private Test sourceTest;
...}
#Entity
public class Test {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
private String name;
private String shortname;
...}
I have a List<TestPair> that i want to persist using spring boot CrudRepository.
TestPair's contain Test's and these Test's are the same along some of the TestPair's.
When i use the saveAll method, it persists the objects but the Test's that are equal it inserts new one's, creating lots of repeating elements in the db.
I've create the equals and hashcode for this classes.
Check the auto generation logic for both the ids. If it is auto incremental then all the created entity will be different hence new entry is getting created every time.
I've found a solution.
Instead of using the crud saveAll for the Hashset, i'm saving one by one.
for(TestPair tPair : TPairs){
testRepository.save(tPair.getSourceTest());
testRepository.save(tPair.getTargetTest());
testPairRepository.save(tPair);
}
And changed the classes to:
#Entity
public class TestPair implements Serializable {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
#OneToOne(cascade = {CascadeType.MERGE})
#JsonProperty("target_Test")
private Test targetTest;
#OneToOne(cascade = {CascadeType.MERGE})
#JsonProperty("source_Test")
private Test sourceTest;
}
#Entity
public class Test {
private String name;
#Id
private String shortname;
}
This way hibernate merges the objects, not creating new one's. Thank you all!
I can't understand how works oneToMany and manyToOne in JPA. For a sample I have to entity.
#Entity
public class Customer {
#Id
#GeneratedValue
private long id;
private String name;
private List<Skills> skillList
}
and another one
#Entity
public class SkillList {
private String skillName;
private byte skillLevel;
}
How to correct link this entities? Also If anyone can explain it in an accessible way.
In database one to many relationship is achieved by foreign key.
In order to link two entities in Java according to JPA specification you should use #ManyToOne annotation or both #ManyToOne and #OneToMany if you need bidirectional association.
#Entity
public class Customer {
#Id
#GeneratedValue
private Long id;
private String name;
#OneToMany(mappedBy = "customer")
private List<Skill> skills;
}
#Entity
public class Skill {
#Id
#GeneratedValue
private Long id;
private String skillName;
private byte skillLevel;
#ManyToOne
private Customer customer;
}
It will generate two tables in the database. Table SKILL has column CUSTOMER_ID which relates to CUSTOMER table.
I am a new bee in Hibernate and I am using PostgreSQL 9.3, JDK 1.7, Hibernate 4.0.2
I am trying to save a Customer who Has-a relationship with Address i.e., One-To-Many Relation.
While saving the Customer i am getting the Exception:
javax.persistence.PersistenceException: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.cust.entities.Address
Customer Entity:
#Entity
#Table(name="customer")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "CustomerIdSeq", sequenceName = "c_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CustomerIdSeq")
#Column (name="c_id")
private Long cId;
#Column(name="cname")
private String cname;
//bi-directional many-to-one association to Address
#OneToMany(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn(name="c_id")
private List<Address> address;
//getters and setters
}
Address Entity:
#Entity
#Table(name="address")
public class Address {
#Id
#Column(name="c_id")
private Long cId;
#ManyToOne
#PrimaryKeyJoinColumn(name="c_id", referencedColumnName="c_id")
private Customer customer;
#Column(name="street")
private String street;
#Column (name="city")
private String city;
//getters and setters
public void setCustomer(Customer customer) {
this.customer= customer;
this.cId= customer.getCId();
}
}
I had tried some thing which is similar to Java Persistence/Identity & Sequencing
I suspect that the Address record doesn't have an ID when calling save().
You're missing the #GeneratedValue tag in that class, and if not specified, it defaults to "assigned" value.
If you're not assigning a value to Address.cId before calling save(), you'll see this problem. Post all relevant code if this isn't the cause of the issue.
EDIT: Looking at your table structure, Address should really have it's own ID in the schema design, and have a foreign key(FK) reference to Customer.ID.
Form the comments to the previous answer and from your existing table structure, you may want to consider mapping Address as an Embeddable rather than as an Entity:
This is similar to a OneToMany, except the target object is an
Embeddable instead of an Entity. This allows collections of simple
objects to be easily defined, without requiring the simple objects to
define an Id or ManyToOne inverse mapping. ElementCollection can also
override the mappings, or table for their collection, so you can have
multiple entities reference the same Embeddable class, but have each
store their dependent objects in a separate table.
http://en.wikibooks.org/wiki/Java_Persistence/ElementCollection
The mappings would then be as follows. Address will have no persistent identity of its own and can only exist as part of an Entity - currently customer but no reason you cannot use it with other entities requiring an address.
Customer:
#Entity
#Table(name="customer")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "CustomerIdSeq", sequenceName = "c_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CustomerIdSeq")
#Column (name="c_id")
private Long cId;
#Column(name="cname")
private String cname;
#ElementCollection
#CollectionTable(name = "customer_address", joinColumns = #JoinColumn(name = "c_id")
private List<Address> addresses;
}
Address:
#Embeddable
public class Address {
#Column(name="street")
private String street;
#Column (name="city")
private String city;
}