Hibernate replaces an embedded class to migrate existing data

I'm at a loss here and maybe this is something obvious, because my Hibernate experience is weaker than other areas.

The legacy code has a Hibernate @Entity Foo class. One of its properties is the following:

 private OldBar bar = new OldBar(); 

OldBar is a @Embeddable class that uses a single column, foobar :

 @Embeddable public class OldBar { private String fooBar; @Column(length = 10, nullable = false) private String getFooBar() { return fooBar; } @SuppressWarnings("unused") private void setFooBar(String fooBar) { this.fooBar = fooBar; } } 

The initial problem was that I needed to do something with OldBar.fooBar , but the original design had limitations and had this field private, which prevented me from subclassing it, so I had to create a whole class, NewBar , replace another and gain access to the private field. I thought that since NewBar also Embeddable and has the same @Column notation, I could just swap the field in the Foo class:

 private NewBar bar = new NewBar(); 

I wanted to do this because I have existing data in the foobar column, and I wanted to transparently use this data with NewBar instead of OldBar .

Through the trace logs, I saw that Foo() is created with its default version of NewBar() , as you would expect when the constructor is called. However, according to the time code, calling Foo.getBar() , for some reason, bar is null ! I assume that Hibernate is null for some reason, but why doesn't Hibernate read data from the foobar column and create an instance of NewBar ? Why does it work again when I put an OldBar instead of a NewBar ? Is there really nothing said in the database itself about which of the @Embeddable classes @Embeddable mapped to a column, is there?

Update: it is becoming strange and unfamiliar. Sometimes I will give the code for the night, and the next day it works! Or the next day it won’t work! Now this did not work (i.e., the foobar property was set to null instead of the value in the database), so I made the ExactCopyOfOldBar class and placed it instead of OldBar . Everything went perfectly! Therefore, I return to NewBar , simply NewBar my temporary changes. It still worked when it wasn’t before! Is there some kind of cache where Hibernate serializes the values ​​and doesn't get them from the database? It is very strange.

Update: Now I can no longer run NewBar . I create OtherBar , which is basically identical to NewBar , except that it has a different name, and I plug it in and it works by reading the inline correctly. I switch back to NewBar and I get null again. What's happening?

Note that Foo loaded via net.databinder.auth.hib.AuthDataApplication.getUser(String username) , which is quite simple:

 return (DataUser) Databinder.getHibernateSession().createCriteria(getUserClass()) .add(Restrictions.eq("username", username)).uniqueResult(); 

I checked again and again that the Foo (user) table has one row with the correct data, and most importantly, the foobar field contains the data. Why does Hibernate return me a Foo with a null foobar field? Why NewBar just switching from NewBar to OtherBar make it work again? Why does it work all day and then stops working after I left it for the night?

+6
source share
1 answer

This may be the answer; I will have to wait a few days to see if this really fixes the problem. There are actually two parts.

First, for full disclosure, my NewBar class was actually a subclass of AbstractBar . In the end, I wanted to have different types of embeddable bars, so I placed @Embeddable at the AbstractBar level, not at the NewBar level, and placed a private foobar field at the AbstractBar level. The funny thing is that it worked for a while. And, as I mentioned, sometimes I return the next day, and Hibernate does not load the foobar field. I do not understand why he did not work all the time or did not work even once.

Secondly, when I tried to get rid of this hierarchy in order to eliminate one source of the problem, I configured AbstractBar and NewBar , but forgot to bring @Embeddable from AbstractBar to NewBar , so Hibernate did not see that it was an embedded class, and did not know how load a string into the NewBar field without @Embeddable . This is why OtherBar (with @Embeddable annotation) worked, but not NewBar (without @Embeddable annotation). I understand it. Why Hibernate did not warn me that he cannot understand how to load the field, I do not know.

So, to summarize, Hibernate will not load the nested field if you left the @Embeddable annotation from the class. Regarding the original problem, I can only guess that @Embeddable is flaky when trying to use it in a class hierarchy and that you are better off not storing all nested fields at the same level in an embedded class. Hope this question. Let's see if he continues to work tomorrow.

+1
source

Source: https://habr.com/ru/post/913275/


All Articles