i'm newbie in Hibernate and i need help.
I have table called Kasa with 3 attributes - id, address and account_id. In my table i have 12 rows.
I want to map this using Hibernate and add new one using Java so I did this:
#Entity
#Table(name = "kasa")
public class Kasa {
#Id
#GeneratedValue(generator = "incrementor")
#GenericGenerator(name = "incrementor", strategy = "increment")
#Column(name = "ID_KASA")
private int id;
#Column(name = "ADRES")
private String adres;
#Column(name = "ID_KONTO")
private int id_konta;
}
I have also getters and setters but no need to copy that.
Now i would like to add new row to my db, like this:
EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("org.hibernate.jpa");
Kasa kasa = new Kasa();
kasa.setId(1);
kasa.setAdres("Kolorowaa");
kasa.setId_konta(2);
EntityManager entityManager =
entityManagerFactory.createEntityManager();
entityManager.persist(kasa);
entityManager.getTransaction().commit();
entityManagerFactory.close();
And I get error like this:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: model.beans.Kasa
It is pointing on this line: entityManager.persist(kasa);
I think the problem can be with ID of my 'Kasa' class because it is generated automatically.
For my configuration i am using persistence.xml file - connection with db works fine. Pls help :)
Don't set the ID! If you do that, JPA things kasa is already in the database.
Database-id must be set by JPA. There for you have to define some strategy how the
key schould be calculated. That's what all theses... #Generate... tags do.
Related
I try to cascade-persist the following two JPA entities (getters/setters and other fields ommited):
#Entity
public class TestEntity {
#Id #GeneratedValue
private Integer id;
private String name; // field only necessary so there is at least one mapping in the table
#ElementCollection
#MapKeyJoinColumn(name="PROPERTY_KEY", referencedColumnName="ID")
#Column(name="PROPERTY_VALUE")
#CollectionTable(name="PROPERTIES")
private Map<TestKey, String> properties = new HashMap<>();
}
#Entity
public class TestKey {
#Id #GeneratedValue
private Integer id;
private String name;
}
This is the code I use to persist the entity:
EntityManager em = ...
em.getTransaction().begin();
TestKey key = new TestKey();
key.setName("some key");
TestEntity entity = new TestEntity();
entity.getProperties().put(key, "some value");
em.persist(entity);
em.getTransaction().commit();
em.close();
But when I do this, I get the following exception:
java.lang.IllegalStateException: During synchronization a new object was found through a relationship
that was not marked cascade PERSIST: TestKey
I am able to fix this by persisting the key before persisting the entity like so:
[...]
em.persist(key); // <<-- line added to previous example
em.persist(entity);
em.getTransaction().commit();
em.close();
This code works as expected and persists both the TestEntity and the TestKey.
Is it somehow possible to cascade-persist the entity without explicitly persisting the key - am I perhaps doing something wrong here?
I actually thought that all #ElementCollection mappings are automatically cascade-persisted. I came to this conclusion from the follwing statements:
https://wiki.eclipse.org/EclipseLink/Examples/JPA/2.0/ElementCollections
Their is no cascade option on an ElementCollection, the target objects
are always persisted, merged, removed with their parent.
https://stackoverflow.com/a/19517505/3270595:
You don't need #ManyToMany annotation here. Operations on
ElementCollections are always cascaded.
I'm using EclipsLink version 2.5.2.v20140319-9ad6abd 2.7.5.v20191016-ea124dd158.
Why Spring JPA does not initialize LAZY property MyChildEntity.myParentEntity (all fields are null)?
I tried to use Hibernate.initialize and #Transactional, but that doesn't help.
my service:
#Service
#Transactional
public class MyService {
#Resource
private MyChildEntityRepository myChildEntityRepository;
#Resource
private MyParentEntityRepository myParentEntityRepository;
#PostConstruct
public void init() {
MyParentEntity p = myParentEntityRepository.save(new MyParentEntity("my name"));
myChildEntityRepository.save(new MyChildEntity(p, "first value"));
myChildEntityRepository.save(new MyChildEntity(new MyParentEntity(1L, "another name"), "another value"));
// At this point both MyChildEntity's are in database and have correct foreign key value
List<MyChildEntity> result = myChildEntityRepository.findAll();
//even this doesn't help, myParentEntity property still has all fields equals to null
Hibernate.initialize(result.get(0).getMyParentEntity());
MyParentEntity p2 = result.get(0).getMyParentEntity();
//trigger proxy's method to initialize lazy field
System.out.print(p2.getName()); // null
System.out.println(p2.getId()); // null
// PROBLEM: p2 has all fields equals null
// the same for result.get(1)
// BUT, this works correct - returns (1L, "my name") entity
myParentEntityRepository.findAll();
}
}
child entity:
#Entity
public class MyChildEntity {
#Id
#SequenceGenerator(sequenceName = "CHILD_SEQ", name = "ChildSeq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ChildSeq")
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "my_parent_entity_id", referencedColumnName = "id")
private MyParentEntity myParentEntity;
#Column
private String value;
// constructors, getters, setters...
parent entity:
#Entity
public class MyParentEntity {
#Id
#SequenceGenerator(sequenceName = "WORKFLOW_SEQ", name = "WorkflowSeq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "WorkflowSeq")
private Long id;
#Column
private String name;
//constructors, getters, setters...
The fetch attribute indicates when the related entities should be retrieved from the
database using the javax.persistence.FetchType enum. FetchType.EAGER means that the JPA
provider must retrieve the values when the entity is retrieved. On the other hand, FetchType.LAZY
serves as a hint to the JPA provider that it can wait and fetch the values only when the property
is first accessed (which may be never, thus saving a trip to the database). However, JPA providers
are not required to support lazy loading, so these values may be loaded eagerly anyway.
Source: Professional Java for Web Applications by Nicholas S Williams
edit:
I really apologize I took this long. Here is what I think is wrong. I don't see an instance of child entity in parent entity. It should look like this:
public class MyParentEntity {
... //other fields
#OneToMany(fetch = FetchType.LAZY, mappedBy = "myParentEntity")
private Set<MyChildEntity> myChildEntities = new HashSet<MyChildEntity>;
... //other fields or constructors or getters or setters
...
}
I hope this works. If not, then in your MyChildEntity class, there is a weird annotation inside #JoinColumn called referencedColumnName. I don't know what that is. Please remove it.
Thanks
I am attempting to insert some fake data into an SQL Server Express database. I am using some simple code like this:
#Entity
#Table(name = "People")
public class Peeps implements Serializable {
#Id
#Column(name = "ID", columnDefinition = "Decimal(10,0)")
private String id;
#Column(name = "PERSON_NAME")
private String name;
}
I call the entity manager to create the above class as follows:
private EntityManager em = createManager();
private EntityTransaction utx = em.getTransaction();
final Peeps entity = new Peeps();
entity.setId("10002");
entity.setName("Joe");
utx.begin();
em.persist(entity);
utx.commit();
However, when doing this, I get an error::
Cannot insert explicit value for identity column in table 'People' when IDENTITY_INSERT is set to OFF
So what I tried doing is something like this:
em.createNativeQuery("SET IDENTITY_INSERT People ON").executeUpdate();
em.persist(entity);
em.createNativeQuery("SET IDENTITY_INSERT People OFF").executeUpdate();
However, I still get the same error. My intuition leads me to believe that the connection is not being shared. Is there something I can do to instruct hibernate to set IDENTITY_INSERT to ON before I invoke my persistence?
You are missing the next line under your id field:
#GeneratedValue(strategy=GenerationType.IDENTITY)
So your id field should look like this:
#Entity
#Table(name = "People")
public class Peeps implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "ID", columnDefinition = "Decimal(10,0)")
private String id;
#Column(name = "PERSON_NAME")
private String name;
}
Second, you are not supposed to set an ID to your entity by yourself, the ID will be generated automatically when you'll persist it using hibernate.
so get rid of: entity.setId("10002");
and just do this:
private EntityManager em = createManager();
private EntityTransaction utx = em.getTransaction();
final Peeps entity = new Peeps();
entity.setName("Joe");
utx.begin();
em.persist(entity);
utx.commit();
something else make sure that you configured your primary key in your DB table, with auto increment.
Some preconditions:
I am not using Oracle DB sequence generator. Instead of it, I rely on the Hibernate sequence generator e.x.
#Entity
#Table(name = "JPA_ENTITY_A")
#GenericGenerator(name = "system-uuid", strategy = "uuid2")
public class JpaEntityA{
#Id
#Type(type = "uuid-binary")
#GeneratedValue(generator = "system-uuid")
private UUID id;
#Column(name="NAME_WITH_ID")
String nameWithGeneratedId;
}
What I want is to persist the following generated value into the column "NAME_WITH_ID": this.nameWithGeneratedId+this.id
Is it feasible to do the following:
public String getNameWithGeneratedId(){
return this.nameWithGeneratedId+this.id;//hope that the returned value will be persisted
}
Or is it possible to retrieve in advance before persisting entity to the DB generated id? If yes, then how can I accomplish it? (based on the comments below it is not possible to do it)
Thx in advance.
You can't; the act of persisting itself is what creates the ID.
In your case, which uses a UUID generator, I think you can use the Lifecycle interface and implement the onSave method returning NO_VETO.
e.g.
#Entity
public MyEntity implements Lifecycle {
#Id
#GeneratedValue
private UUID id;
...
public boolean onSave(final Session session) throws CallbackException {
// here your entity will have an ID
return Lifecycle.NO_VETO;
}
...
}
The onSave method will be called before saving the entity and after generating the ID.
In my database table Attribute, I will have a list of data loaded first. Every time, when I want to persist a new record of MyAttribute, I will need to search through the table Attribute first and select the appropriate record from table Attribute before I insert to table MyAttribute.
#Entity
class MyAttribute{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne(targetEntity = Attribute.class)
#JoinColumn(name="attribute_id", referencedColumnName="id")
Attribute detail;
private String greet;
public MyAttribute(){
this.greet = "Hello World.";
this.detail = new MyDbLayer().selectAttributeDetail("first"); //Error is thrown here.
}
//getter & setter
}
#Entity
class Attribute{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Index(name = "name_index")
#Column(unique=true )
private String name;
//getter & setter
}
class MyDbLayer{
private EntityManagerFactory emf;
public MyDbLayer() {
emf = Persistence.createEntityManagerFactory("MyPu");
}
public Attribute selectAttributeDetail(String name) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Query queryGetAttribute = em.createQuery("select a from Attribute a where a.name = :attributeName");
List<AttributeDescription> attributeDescList = queryGetAttribute.setParameter("attributeName", name).getResultList();
AttributeDescription tempAttribute = null;
if (!attributeDescList.isEmpty()) {
tempAttribute = (AttributeDescription) attributeDescList.get(0);
}
em.clear();
em.close();
return tempAttribute;
}
}
I'm not sure why I keep on receiving error like:
javax.persistence.PersistenceException: [PersistenceUnit: MyPu] Unable
to build EntityManagerFactory
Caused by: org.hibernate.MappingException: Could not get constructor
for org.hibernate.persister.entity.SingleTableEntityPersister
Caused by: org.hibernate.InstantiationException: could not instantiate
test object
P.S. This is not the real code that I'm working on, but the structure is more or less the same.
What about making a second construtor for MyAttribute?
public MyAttribute(){
this.greet = "Hello World.";
// this.detail = new MyDbLayer().selectAttributeDetail("first"); //Error is thrown here.
}
public MyAttribute(Attribute detail){
this.greet = "Hello World.";
this.detail = detail;
}
The default constructor is also used by jpa to load persited objects. this can cause unexpected behaviour
It is not in the JPA model to be able to access an EntityManager from an Entity. It can be done, but it can have different behaviors depending on the implementation.
In your case accessing an EntityManager from the no args constructor is never a good idea. Because thats the constructor used by the EntityManager when it loads an Entity. So every time MyAttribute is loaded by an EntityManager you will try to create antoher EntityManager to initialise the detail relationship which will be overwritten by the first EntityManager using the value it loaded from the database.
Usually you should have a service layer which has access to an EntityManager that manages your JPA Entities.