getResultList() generate org.hibernate.TransientObjectException: object references an unsaved transient instance - sql

I'm aware that this problem has been asked several times before. But I believe I have a very different case, I'm currently encountering this error when invoking the getResultList() method, not when persisting.
Note that I'm using:
-javaee6
-seam3-security
-jboss7.1.3
-postgresql
Series of events:
1.) After login, I saved my user in picketlink using the interface org.picketlink.idm.api.User:
setUser(new MyUser(user));
I should be able to retrieve the user using ((MyUser)identity.getuser()).getUser();
2.) Now I have a BusinessAccount entity that has OneToMany relationship with AccounType:
#Entity
#Table(name = "T_ACCOUNT")
public class BusinessAccount extends BaseEntity {
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "ACCOUNT_TYPE_ID")
private AccountType accountType;
}
#Entity()
#Table(name = "T_ACCOUNT_TYPE")
public class AccountType extends BaseEntity {
#Enumerated(EnumType.STRING)
#Column(name = "ACCOUNT_TYPE", length = 20)
private AccountTypeEnum accountTypeEnum;
}
My problem is I have a service: BusinessAccountService that extends BaseService, which calls getAccounts and it throws this error:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
BaseService has:
public User getCurrentUser() {
if(currentUser==null){
try {
currentUser=((MyUser) identity.getUser()).getUser();
} catch(Exception e){
log.warn("getCurrentUser cannot retrieve current user from session identity and currentUser has not been set programmatically");
}
}
return currentUser;
}
And then my dynamically generated query is like this:
select distinct a from BusinessAccount a where a.accountType.accountTypeEnum=:a_accountType_accountTypeEnum and (a.accountType in (:a_accountType0))
Param name:a_accountType_accountTypeEnum value:serviceProvider
Param name:a_accountType0 value:[org.model.accounts.AccountType#1, org.model.accounts.AccountType#2]
and I found out that this line is throwing the error:
and (a.accountType in (:a_accountType0))
Why is that? When I'm only executing a getResultList()?

I think I've found the problem, the AccountType is extending a BaseEntity that has a Version field. When I removed the extend and add Version property in AccountType, I got the same error.
The Version field:
#Version
#Column(name = "VERSION")
private Integer version;
This version field must have an initial value which is 0.

Related

Cant get hibernate to update object without EntityExistException being thrown

I am trying to do a bidirectional one to one relation and when updating the AccountExtrasModel on the first save it works fine but when updating I get either an error or the sql statements adds an insert and then a delete instead of an update.
import lombok.*;
import javax.persistence.*;
#ToString
#NoArgsConstructor
#Getter
#Setter
#Entity
#Table(name = "Account")
public class AccountModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long Account_ID;
#Column(nullable = false, updatable = false)
private String name;
#Column(nullable = false, unique = true, updatable = false)
private String email;
#Column(nullable = false, updatable = false)
private String password;
#OneToOne(mappedBy = "accountModel", cascade = CascadeType.ALL, orphanRemoval = true)
private AccountExtrasModel accountExtras;
public AccountModel addExtras(AccountExtrasModel accountExtrasModel) {
accountExtrasModel.setAccountModel(this);
this.setAccountExtras(accountExtrasModel);
return this;
}
}
import lombok.*;
import javax.persistence.*;
#Setter
#Getter
#NoArgsConstructor
#ToString
#Entity
#Table(name = "AccountExtras")
public class AccountExtrasModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long ID;
#OneToOne(fetch = FetchType.LAZY)
#MapsId
private AccountModel accountModel;
#Lob
private String description;
private String[] myVideos;
private String[] likedVideos;
private String imageReference;
}
If i change the #MapsId to #JoinColumn in AccountExtrasModel then i get the desired result but what its doing is inserting a new row and linking it to acccount and then deleting the old row instead of doing an update.
This is the error im getting:
{
"timestamp": "2018-04-26T18:19:01.657+0000",
"status": 500,
"error": "Internal Server Error",
"message": "A different object with the same identifier value was already associated with the session : [com.alttube.account.models.AccountExtrasModel#1]; nested exception is javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.alttube.account.models.AccountExtrasModel#1]",
"path": "/update_account"
}
What can i do to get the desired result which is to simply perform an update on the accountExtrasModel to the corresponding account to which it belongs?
If you update an AccountModel instance by setting a new instance of AccountExtrasModel, as you do in addExtras(), then it is normal to have a delete+insert. By updating the id you would end with orphaned records.
When you set new values on AccountExtrasModel instance, check if accountExtras is initialized. If not, do the addExtras() stuff. If it is, do not replace it, just change it, so hibernate will generate an update on the extras table (but keep the record id unchanged).
Instead of use the method save try use the method merge, because in case of object exist in database the framework will update this object.
Case the object don't exist, the framework will insert as normal.
Regards!

Apache Isis: #Property(editing = Editing.ENABLED) doesn't work for ViewModels

I added a property to ViewModel and marked it with Editing.ENABLED.
#DomainObject(
nature = Nature.VIEW_MODEL,
objectType = "homepage.HomePageViewModel"
)
public class HomePageViewModel {
#Setter #Getter
#Property(editing = Editing.ENABLED)
private String editableField;
}
But this field is not editable on UI:
But it works fine for SimpleObject:
Does it work correctly for ViewModel?
Maybe ViewModel shouldn't have any properties?
No, it isn't working correctly for view models... the framework is meant to support this.
The good news is that there is a workaround. If you annotate the class to use the (more flexible) JAXB-style of view model, then it all works as expected.
Here's an updated version of the class; look for annotations starting #Xml...:
#XmlRootElement(name = "compareCustomers")
#XmlType(
propOrder = {
"editableField"
}
)
#XmlAccessorType(XmlAccessType.FIELD)
public class HomePageViewModel {
#XmlElement(required = true)
#Setter #Getter
#Property(editing = Editing.ENABLED)
private String editableField;
public TranslatableString title() {
return TranslatableString.tr("{num} objects", "num", getObjects().size());
}
public List<SimpleObject> getObjects() {
return simpleObjectRepository.listAll();
}
#XmlTransient
#javax.inject.Inject
SimpleObjectRepository simpleObjectRepository;
}
For more on JAXB view models, see the user guide.
Meantime I've raised a JIRA ticket for the issue you've discovered,

Hibernate3 --> Hibernate 4 and issues (Lazy...)

I'm trying to update the libraries of my project (from Hibernate 3.2.1 GA to Hibernate 4.2.8)
This (complex) application use LAZY loading and get the object later only when we need it.
-->it seems to work differently now because I get some org.hibernate.LazyInitializationException: could not initialize proxy - no Session
#Entity
#Table(name = "CLIENTS")
public class Clients {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "INFOIDT", insertable = true, updatable = false)
private Information info;
//...
}
and when I need to know more about the product before using it :
cli.getInfo();
Note that in my persistence.xml I also have the property
hibernate.cache.provider_class set to org.hibernate.cache.EhCacheProvider for a second level cache.
QUESTION : what is the simple way to migrate my existing code with Hibernate4?
(the class given for example above is a fake example to illustrate the many cases using the LAZY loading)
Thank you.
As requested, see my DAO below :
public class MyAppJpaDAO extends GenericJpaDAO implements IMyAppDAO {
protected static Log log = LogFactory.getLog(MyAppJpaDAO.class);
// Entity Manager of the project
#PersistenceContext(unitName = "MyApp.hibernate")
private EntityManager em;
public News readLastNews() {
StringBuffer sql = new StringBuffer("");
sql.append(" select object(n) ");
sql.append(" from News n ");
sql.append(" Where n.flagLastStatus = 'V' ");
sql.append(" order by n.pk.date desc ");
Query aQuery = em.createQuery(sql.toString());
List<News> res = (List<News>) aQuery.getResultList();
if (res != null && res.size() != 0) {
return res.get(0);
}
return null;
}
//...
}
/////////////
public class GenericJpaDAO implements IGenericDAO {
protected static Log log = LogFactory.getLog(GenericJpaDAO.class);
#PersistenceContext(unitName = "MyApp.hibernate")
EntityManager em;
public Object getReference(Class _class, Object _object) {
return em.getReference(_class, _object);
}
public void createObject(Object object) {
try {
em.persist(object);
} catch (LazyInitializationException lie) {
em.merge(em.merge(object));
}
}
public void deleteObject(Object object) {
try {
em.remove(object);
} catch (Exception e) {
em.remove(em.merge(object));
}
}
public void updateObject(Object object) {
em.merge(em.merge(object));
}
//...
}
If you want to use LazyLoading, you need to have the session opened and connected at the time when you calls .getInfo(). org.hibernate.LazyInitializationException occures if you tries to get an entity but the session is disconnected or closed.
I think you have problems with session handling. There is nothing to do with the entities.
If the SessionFactory is configured in a Spring context file, we can use the OpenSessionInViewFilter to keep the session open.
<filter>
<filter-name>Hibernate Session In View Filter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Hibernate Session In View Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Unfortunately, my application is not configured like this...
Interesting...but still not helping
http://www.javacodegeeks.com/2012/07/four-solutions-to-lazyinitializationexc_05.html
But I find something :
1)Hibernate 3.2.1 GA and Spring 2.0
I used to put a Person having a LAZY bag in a Group and when I wanted to get some pencil from the bag of any person of the group, I was able to get it.
2)Hibernate 4.2.8 et Spring 3.2.5.
If I don't explicitely ask to know the content of the bag just after getting the Person and before putting it into the group, I will have the lazy exception.
If someone could explain me why...

Hibernate - one table multiple entities

Firstly, I have read Hibernate - One table with multiple entities?.
However, I would like to map two entities to the same table, but I would like both of them to be entities, which I can select from. What I mean:
One table: Person (id, name, dateOfBirth, city, street, zipcode).
Two Entities: Person (id, name, dateOfBirth), Address (id, city,
street, zipcode).
So it's a 1:1 relationship between Entities, but still 1 table in DB.
If I do it using the proposed solution (component keyword) in the above link, I can't query Address directly (I can access it via Person entity). And I want to be able to do
session.createCriteria(Adres.class)
How do I do that?
UPDATE:
I tried the one-to-one association between entities, in Address mapping:
<one-to-one name="Person " class="model_mapowanie_xml.Person "/>
and in Person mapping:
<one-to-one name="Address" class="model_mapowanie_xml.Address "/>
Both classes have fields referring to the other one. Selecting records works fine for that. However, how can I add in one transaction a record using both entities? (Id is db-generated)
Address ad = new Address();
ad.setProperty("Sydney");
Person p = new Person();
p.setProperty("John");
p.setAddress(ad);
session.save(p);
and only Person part is saved, the address property remains empty.
This is very simple to achieve with JPA and Hibernate.
Let's assume you are using the following book database table:
Mapping entities
Now, you can map two entities: Book and BookSummary to this table.
First, we will create a BaseBook abstract class which will be extended by all entities:
#MappedSuperclass
public abstract class BaseBook<T extends BaseBook> {
#Id
#GeneratedValue
private Long id;
#NaturalId
#Column(length = 15)
private String isbn;
#Column(length = 50)
private String title;
#Column(length = 50)
private String author;
public Long getId() {
return id;
}
public T setId(Long id) {
this.id = id;
return (T) this;
}
public String getIsbn() {
return isbn;
}
public T setIsbn(String isbn) {
this.isbn = isbn;
return (T) this;
}
public String getTitle() {
return title;
}
public T setTitle(String title) {
this.title = title;
return (T) this;
}
public String getAuthor() {
return author;
}
public T setAuthor(String author) {
this.author = author;
return (T) this;
}
}
Now, the BookSummary entity simply extends the BaseBook superclass and adds no additional entity attribute.
#Entity(name = "BookSummary")
#Table(name = "book")
public class BookSummary extends BaseBook<BookSummary> {
}
On the other hand, the Book entity extends the BaseBook superclass and maps the properties attribute.
#Entity(name = "Book")
#Table(name = "book")
#TypeDef(
name = "jsonb",
typeClass = JsonBinaryType.class
)
#DynamicUpdate
public class Book extends BaseBook<Book> {
#Type(type = "jsonb")
#Column(columnDefinition = "jsonb")
private String properties;
public String getProperties() {
return properties;
}
public Book setProperties(String properties) {
this.properties = properties;
return this;
}
public ObjectNode getJsonProperties() {
return (ObjectNode) JacksonUtil
.toJsonNode(properties);
}
}
Persisting entities
This way, you can persist either a Book entity:
entityManager.persist(
new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea")
.setProperties(
"{" +
" \"publisher\": \"Amazon\"," +
" \"price\": 44.99," +
" \"publication_date\": \"2016-20-12\"," +
" \"dimensions\": \"8.5 x 1.1 x 11 inches\"," +
" \"weight\": \"2.5 pounds\"," +
" \"average_review\": \"4.7 out of 5 stars\"," +
" \"url\": \"https://amzn.com/973022823X\"" +
"}"
)
);
or a BookSummary:
entityManager.persist(
new BookSummary()
.setIsbn("978-1934356555")
.setTitle("SQL Antipatterns")
.setAuthor("Bill Karwin")
);
Fetching entities
You can fetch the BookSummary entity:
BookSummary bookSummary = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(BookSummary.class)
.load("978-9730228236");
assertEquals(
"High-Performance Java Persistence",
bookSummary.getTitle()
);
or the Book entity if you want:
Book book = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(Book.class)
.load("978-9730228236");
assertEquals(
"High-Performance Java Persistence, 2nd edition",
book.getTitle()
);
Conclusion
So mapping multiple entities to the same database table, not only that it allows us to fetch data more efficiently, but it also speeds up the dirty checking process as Hibernate has to inspect fewer entity properties.
The only drawback of using this approach is that you have to make sure you don’t fetch more than one entity type for the same database table record, as otherwise, this can cause inconsistencies when flushing the Persistence Context.
You should be able to do it using #Table annotation. These entites will be treated as different entites but will be mapped onto same table.
#Entity
#Table(name="PERSON_TABLE")
class Person {}
#Entity
#Table(name"PERSON_TABLE")
class Address {}
Edit:
If you want to save both entities in one transaction you either have to explicitly save them using Session or set cascade property to cascade operations on relationship. I guess you want to cascade operations on Address when you do something on Person. See CascadeType if you use annotations.
In your hbm it would look like
<one-to-one name="Person" class="model_mapowanie_xml.Person" cascade="all"/>

Why do not #JsonTypeInfo work together with #JsonIdentityInfo?

#JsonIdentityInfo works as expected with the following classes:
Baseclass:
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "uuid")
public class TestEntityBas {
#JsonProperty
public String uuid = "0001";
}
Subclass:
public class TestEntityGoa extends TestEntityBas {
#JsonProperty
public String texten = "This is text!";
}
Container class:
public class TestEntity {
#JsonProperty
String stringer = "Hej hopp!";
#JsonIdentityReference(alwaysAsId = true)
public TestEntityGoa goa = new TestEntityGoa();
}
The result is as expected:
{"stringer":"Hej hopp!","goa":"0001"}
When I add #JsonTypeInfo to the base class like this:
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="#class")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "uuid")
public class TestEntityBas {
#JsonProperty
public String uuid = "0001";
}
Now the entire TestEntityGoa get serialized like this:
{"stringer":"Hej hopp!","goa":{"#class":"com.fodolist.model.TestEntityGoa","uuid":"0001","texten":"This is text!"}}
I expect the first result even when I use #JsonTypeInfo and #JsonIdentityInfo in the same class. What am I doing wrong?
I can't see anything obviously wrong here, so you may have found a bug. Combination of type and identity info is bit tricky to handle so there may be edge cases that do not yet work as intended, so could you file a bug at Github issue tracker for this?