There's a lot one can find about this googling a bit but I haven't quite found a workable solution to this problem.
Basically what I have is a big CLOB on a particular class that I want to have loaded on demand. The naive way to do this would be:
class MyType {
// ...
#Basic(fetch=FetchType.LAZY)
#Lob
public String getBlob() {
return blob;
}
}
That doesn't work though, apparently due to the fact I'm using oracle drivers, i.e. Lob objects aren't treated as simple handles but are always loaded. Or so I've been led to believe from my forays. There is one solution that uses special instrumentation for lazy property loading, but as the Hibernate docs seem to suggest they're less than interested in making that work correctly, so I'd rather not go that route. Especially with having to run an extra compile pass and all.
So the next solution I had envisioned was separating out this object to another type and defining an association. Unfortunately, while the docs give conflicting information, it's apparent to me that lazy loading doesn't work on OneToOne associations with shared primary key. I'd set one side of the association as ManyToOne, but I'm not quite sure how to do this when there's a shared primary key.
So can anybody suggest the best way to go about this?
According to this only PostgreSQL implements Blob as really lazy. So the best solution is to move the blob to another table. Do you have to use a shared primary key? Why don't you do something like this:
public class MyBlobWrapper {
#Id
public Long getId() {
return id;
}
#Lob
public String getBlob() {
return blob;
}
#OneToOne(fetch=FetchType.LAZY,optional=false)
public MyClass getParent() {
return parent;
}
}
Instead of doing equilibristics with hibernate annotations, one may just try converting the field from String into Clob (or Blob):
#Lob
#Basic(fetch=FetchType.LAZY)
#Column(name = "FIELD_COLUMN")
public Clob getFieldClob() {
return fieldClob;
}
public void setFieldClob(Clob fieldClob) {
this.fieldClob = fieldClob;
}
#Transient
public String getField()
{
if (this.getFieldClob()==null){
return null;
}
try {
return MyOwnUtils.readStream(this.getFieldClob().getCharacterStream());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void setField(String field)
{
this.fieldClob = Hibernate.createClob(field);
}
Worked for me (the field started to load lazily, on Oracle).
Since you appear to be using Hibernate I wonder if your problem is related to the following Hibernate feature:
Using Lazy Properties Fetching
Hibernate3 supports the lazy fetching of individual properties. This
optimization technique is also known as fetch groups. Please note that
this is mostly a marketing feature; optimizing row reads is much more
important than optimization of column reads. However, only loading
some properties of a class could be useful in extreme cases. For
example, when legacy tables have hundreds of columns and the data
model cannot be improved.
Lazy property loading requires buildtime bytecode instrumentation. If
your persistent classes are not enhanced, Hibernate will ignore lazy
property settings and return to immediate fetching.
See Bytecode Instrumentation for Hibernate Using Maven.
Old post, but only one that helped me, thanks to #TadeuszKopec answer.
Looks like it is hard to do lazy loading of blob with JPA. I tried #OneToOne association, but it complicates more than help.
I just moved the bytes to another class, with no association with MyClass (parent. Same table, same id):
#Entity
#Table(name="MyTable")
public class MyBlobWrapper{
#Id
#Column(name = "id") // id of MyTable, same as MyClass
private Long id;
#Lob
private byte[] bytes;
}
#Entity
#Table(name="MyTable")
public class MyClass{
#Id
#Column(name = "id")
private Long id;
// other fields .....
}
Just remember to flush parent, before saving the blob:
em.persist(parent);
em.flush();
em.merge(new MyBlobWrapper(parent_id,new byte[1000]));
Now I can load the pdf alone:
String query1 = " select PDF from MyBlobWrapper PDF where PDF.id = :id";
I am just beginner with JPA, hope that helps.
Related
I'm trying to use the jOOQ fetchInto() method to map to an existing Hibernate model Organization (class and its inheritances are below).
Organization organization = jooq().select().from(ORGANIZATION).fetchOne().into(Organization.class);
The problem I have is that I can't really understand what happens in DefaultRecordMapper as I feel I'm not entirely familiar with all the terms that are used. I'm trying to figure out how it applies to the Hibernate classes that are in my codebase.
So far what I've tried:
Use the jOOQ generated POJO's to see if it retrieves and maps the data at all (works).
Add a constructor, getters and setters to the Organization Hibernate model.
Add #Column annotation to name in the Organization Hibernate model.
What works:
id field gets mapped correctly.
What doesn't work:
name field doesn't get mapped (null).
createdAt and modifiedAt fields do not get mapped (null).
My question is: Is there something I am overlooking with the mapping and what are the things I should look at concerning the classes, fields, constructors and annotations with Hibernate models? I want to eventually map all the Hibernate models in the codebase and use fetchInto to do that.
Thanks! :)
#Entity
public class Organization extends BaseModel {
#Required public String name;
//... a lot of other code
}
#MappedSuperclass
public class BaseModel extends Model {
/** The datetime this entity was first saved. Automatically set by a JPA prePersist */
#NoBinding
#Column
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
public DateTime createdAt;
/** The datetime this entity was last modified. Automatically set by a JPA preUpdate */
#NoBinding
#Column
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
public DateTime modifiedAt;
//...
}
#MappedSuperclass
public class Model extends GenericModel { // Both Model and GenericModel are from the Play Framework
#Id
#GeneratedValue
public Long id;
public Model() {
}
public Long getId() {
return this.id;
}
public Object _key() {
return this.getId();
}
}
jOOQ doesn't support all the many JPA and Hibernate specific annotations. Historically, it supported a few JPA annotations (because why not), but full interop would be excessive and investing product development time in the wrong places. jOOQ is by no means a JPA implementation.
Step 0: Why didn't (some) of the mappings work?
As mentioned before, not all JPA specification is implemented. For example, a known issue is that #Column annotations are still mandatory in jOOQ:
https://github.com/jOOQ/jOOQ/issues/4586
There might be other such limitations, which could be considered bugs. Feel free to report them if you want to continue down this path: https://github.com/jOOQ/jOOQ/issues/new/choose
But things like #MappedSuperclass or #Type are unlikely to ever be supported by jOOQ.
Step 1: Do you really need it?
You've decided to create and run your query with jOOQ. I imagine your actual query is much more complex than what you're showing, because for that particular query, you don't need jOOQ.
Do you really need to map to Hibernate entities? Because even when you use Hibernate, the recommended approach is to use entities only when you're going to modify them and store the delta back to the database. If that's the case, see step 2 below. If it's not the case, why not use jOOQ's own mapping functionality to work with any style of jOOQ supported POJO?
Step 2: Use Hibernate to execute the jOOQ query
If you're using jOOQ only to build a rather complex SQL query and you need Hibernate entities as a result, then use Hibernate to execute the jOOQ query as documented here. A small utility should be enough:
public static <E> List<E> nativeQuery(EntityManager em, org.jooq.Query query, Class<E> type) {
Query result = em.createNativeQuery(query.getSQL(), type);
List<Object> values = query.getBindValues();
for (int i = 0; i < values.size(); i++)
result.setParameter(i + 1, values.get(i));
return result.getResultList();
}
I have an entity with two Embedded classes of the same type and which one has an ElementCollection of the same type two. The business logic is apparently correct, but I am experiencing some problems with lack of knowledge in JPA, I guess.
Let's check my classes:
#Entity
public class Etapa extends EntidadeBase {
#Embedded
private CronogramaDeDesembolso cronogramaDeReceita;
#Embedded
private CronogramaDeDesembolso cronogramaDeDespesa;
}
#Embeddable
public class CronogramaDeDesembolso {
#ElementCollection
private List<Parcela> parcelas;
}
I am receiving the following error log.
Caused by: org.hibernate.HibernateException: Found shared references
to a collection:
nexxus.convenioestadual.dominio.planodetrabalho.etapa.Etapa.cronogramaDeReceita.parcelas
Do you guys have any clue of what is wrong and how can I fix it?
EDIT:
Due comments I did this edit and it do not worked too
#Entity
public class Etapa extends EntidadeBase {
#Embedded
#AttributeOverride(name = "parcelas", column = #Column(name = "parcelasReceita"))
private CronogramaDeDesembolso cronogramaDeReceita;
#Embedded
#AttributeOverride(name = "parcelas", column = #Column(name = "parcelasDespesa"))
private CronogramaDeDesembolso cronogramaDeDespesa;
}
Is there any reason why you have decided to use this structure ? Typically when converting an object to an RDBMS you would need to model the relationships. When you use an embeddable it will add the column (or columns) associated with it to the table. So when you do this normally (not collections) it is fine.
When you do a collection it runs into issues. Mainly there is no way to represent a collection in a single row (since this is an entity you could have many of them so effectively for each object you only have one row) & one column. So when you represent a collection you actually have to have a second table with a column referencing it back to the first. It's really the opposite thinking of a normal object. The collection entries need to know what collection they were associated with instead of the collection being knowledgeable of its entries.
So in some POJO you could have and these....
MyListObject {
//Some implementation of things you want to collect
}
MyClass {
List<MyListObject> myListObject;
}
But to model this in JPA you would need to have these represented by two tables.
Your object that will be in the list.
#Entity
MyListObject {
#ManyToOne
#JoinColumn(name = "MY_CLASS_KEY")
private MyClass myClass;
}
Your object/entity that will have the list.
#Entity
MyClass {
#Id
#Column(name = "MY_CLASS_KEY")
private Long myClassKey;
#OneToMany(mappedBy = "myClass")
private List<MyListObject> myString;
}
I hope this helps.
A quick search on Google turned up this in StackOverflow:
JPA Multiple Embedded fields
It would seem as though you have to do some explicit annotation overriding over the fields within the embeddable class. There are some code examples in the linked answer as well that should give you a good idea of where to go.
Cheers,
Say I have the following Java class, which is owned by a vendor so I can't change it:
public class Entry {
private String user;
private String city;
// ...
// About 10 other fields
// ...
// Getters, setters, etc.
}
I would like to persist it to a table, using JPA 2.0 (OpenJPA implementation). I cannot annotate this class (as it is not mine), so I'm using orm.xml to do that.
I'm creating a table containing a column per field, plus another column called ID. Then, I'm creating a sequence for it.
My question is: is it at all possible to tell JPA that the ID that I would like to use for this entity doesn't even exist as a member attribute in the Entry class? How do I go about creating a JPA entity that will allow me to persist instances of this class?
EDIT
I am aware of the strategy of extending the class and adding an ID property it. However, I'm looking for a solution that doesn't involve extending this class, because I need this solution to also be applicable for the case when it's not only one class that I have to persist, but a collection of interlinked classes - none of which has any ID property. In such a scenario, extending doesn't work out.
Eventually, I ended up doing the following:
public class EntryWrapper {
#Id
private long id;
#Embedded
private Entry entry;
}
So, I am indeed wrapping the entity but differently from the way that had been suggested. As the Entry class is vendor-provided, I did all its ORM work in an orm.xml file. When persisting, I persist EntryWrapper.
I don't have much experience with JPA, but I wouldn't extend your base classes, instead I would wrap them:
public class PersistMe<T> {
#Id
private long id;
private T objToWrap;
public(T objToWrap) {
this.objToWrap = objToWrap;
}
}
I can't test it, if it doesn't work let me know so I can delete the answer.
I have an Keyword and a KeywordType as entities. There are lots of keywords of few types. When trying to persist the second keyword of a type, the unique constraint is violated and the transaction is rolled back. Searching SO i found several possibilies (some of them from different contexts, so I'm not sure of their validity here) - this post and this post advise catching the Exception which would be of no use to me as I end up where I started and still need to somehow persist the keyword.
Same applies to locking proposed for a different situaltion here Custom insert statements as proposed in this and this posts wouldn't work proper I guess, since I'm using Oracle and not MySQL and woulnd like to tie the implementation to Hibernate. A different workaround would be trying to retrieve the type first in the code generating the keywords, and set it on the keyword if found or create a new one if not.
So, what would be the best - most robust, portable (for different databases and persistence providers) and sane approach here?
Thank you.
The involved entities:
public class Keyword {
#Id
#GeneratedValue
private long id;
#Column(name = "VALUE")
private String value;
#ManyToOne
#JoinColumn(name = "TYPE_ID")
private KeywordType type;
...
}
and
#Entity
#Table(uniqueConstraints = {#UniqueConstraint(columnNames = { "TYPE" }) })
public class KeywordType {
#Id
#GeneratedValue
private long id;
#Column(name = "TYPE")
private String type;
...
}
Your last solution is the right one, IMO. Search for the keyword type, and if not found, create it.
Catching the exception is not a good option because
it's hard to know which exception to catch and make your code portable across JPA and DB engines
The JPA engine will be in an undetermined state after such an exception, and you should always rollback in this case.
Note however that with this technique, you might still have two transactions searching for the same type in parallel, and then try to insert it in parallel. One of the transaction will rollback, but it will be much less frequent.
If you're using EJB 3.1 and you don't mind serializing this operation, a singleton bean using container managed concurrency can solve the problem.
#Singleton
#ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class KeywordTypeManager
{
#Lock(LockType.WRITE)
public void upsert(KeywordType keywordType)
{
// Only one thread can execute this at a time.
// Your implementation here:
// ...
}
#Inject
private KeywordTypeDao keywordTypeDao;
}
I would go for this option:
A different workaround would be trying
to retrieve the type first in the code
generating the keywords, and set it on
the keyword if found or create a new
one if not.
According to my JPA 2.0 book (and online documentation), I should be able to mix field and property access within a single entity or entity hierarchy. The annotation of #Access on the class specifies the default access. When placed on a field or property getter #Access can specify that the default should be overridden for this field.
#Entity
#Access(AccessType.FIELD)
Class Foo {
#Id
int id;
#Column(name = "myfield")
String myField;
#Column(name = "myProp")
#Access(AccessType.PROPERTY)
public int getMyProp () {
return 3;
}
public void setMyProp (int p) {
// do nothing
}
}
This class should result in a table with three columns. However it doesn't with Hibernate...the "myProp" column is missing from the table because apparently Hibernate takes its field vs property cue from the entity ID and runs with it...totally ignoring the JPA spec with regards to #Access.
Can anyone confirm this or did I make a stupid mistake somewhere?
I've seen similar (not the same but similar) issues like HHH-5004 so I wouldn't exclude that this might be a new one (the TCK doesn't seem exhaustive). But what version of Hibernate are you using? Did you try with the latest?
Based on the docs your code seems to be right. The #Access(AccessType.FIELD) annotation on top is unnecessary, because you annotated the field int id;
This tells hibernate to use field access. I tried a very similar example with annotations and xml config mixed. This leads to the same behaviour, so it's probably a bug in hibernate.
I tried with hibernate 3.5.3