I want to exclude some of the fields in child entity using jpa.
Ex :
Class Person extends Serializable
{
private String firstName;
private String lastName;
private String id;
private PersonalInformation personalInformation;
}
Class PersonalInformation extends Serializable
{
private Date dob;
private List<PersonalDocument> documents;
}
Class PersonalDocument extends Serializable
{
private String fileName;
private int fileSize;
private byte[] fileData;
}
When I tried to get the details of a person, I could get all the information about a person, including PersonalInformation and PersonalDocument list, but since PersonalDocument.fileData can be huge, every time getting this field from DB is impacting the performance.
So I wanted to ignore/exclude PersonalDocument.fileData field while reading only, I wanted to know how to write the jpa query for the same.
One solution then would be to have the file data lazily fetched i.e. fetched on demand from the database when you access the field. Note that JPA specification does not require that provider implementations actually support the lazy loading of individual fields (rather than associations): any directives in this area can only be considered as a hint to the persistence provider.
I know that Hibernate does support the lazy loading of fields and there are lots of similar questions in this area but I have been unable to find a definitive answer about exactly what is required.
Firstly, however you need to mark the field with the #Lob annotation (http://docs.oracle.com/javaee/6/api/javax/persistence/Lob.html)
import javax.persistence.Lob;
public class PersonalDocument implements Serializable
{
private String fileName;
private int fileSize;
#Basic(fetch=LAZY) //optional??
#Lob
private byte[] fileData;
}
The following suggests that #Lob is lazy by default and so we may not need the additional #Basic(fetch=LAZY) however no harm in adding it anyway.
https://hibernate.atlassian.net/browse/ANN-418
While some similar Stack Overflow questions appear to report that adding #Lob is all that is required to have such fields lazily loaded, the Hibernate docs themselves note that lazy field loading requires byte code enhancement.
https://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/
To enable property level lazy fetching, your classes have to be
instrumented: bytecode is added to the original class to enable such
feature, please refer to the Hibernate reference documentation. If
your classes are not instrumented, property level lazy loading is
silently ignored.
So, in summary:
Add #Lob and see if it works.
If not, add #Basic(fetch=LAZY) and see if it works.
if not, either add byte code enhancement to your build.
https://docs.jboss.org/hibernate/orm/5.0/topical/html/bytecode/BytecodeEnhancement.html
Related
I am working on a EclipseLink application, which uses Oracle Objects as IN and OUT parameters (while invoking stored procedure). As you know we have #Struct annotations available in Eclipselink for representing Oracle Object, I used it and it is working perfectly. But, looks like order of the fields declared in Struct annotated class matters a lot to map to correct field in oracle object. This causes maintenance issues and very difficult to code when object's properties are more. Is there a way in Eclipselink to say map Structure fields based on name and not with order.
Ex: Below is my Struct class. If by chance I declare variables in different order from fields list, wrong/incorrect mappings will happen while fetching records from stored proc. Its always mapping values to fields from top to bottom. #Column name annotation is not able to solve this issue.
#Struct(name = "REC_OBJECT",
fields = {"TRANS_ID", "PROJECT_ID", "LANGUAGE_CODE", "DESCRIPTION"})
#Embeddable
public class Master {
#Column(name = "PROJECT_ID")
private String projectId;
#JsonIgnore
#Column(name = "TRANS_ID")
private String transactionId;
#Column(name = "LANGUAGE_CODE")
private String languageCode;
#Column(name = "DESCRIPTION")
private String description;
}
Please suggest solution for this. Thank you.
I have a JPA #Entity class Place, with some properties holding some information about a place, such as name of place, description, and URLs of some images.
For the URLs of images, I declare a List<Link> in my entity.
However, I am getting this error:
Basic attribute type should not be a container.
I tried to remove #Basic, but the error message is still there. Why does it shows this error?
You can also use #ElementCollection:
#ElementCollection
private List<String> tags;
You are most likely missing an association mapping (like #OneToMany) and/or #Entity annotation(s).
I had a same problem in:
#Entity
public class SomeFee {
#Id
private Long id;
private List<AdditionalFee> additionalFees;
//other fields, getters, setters..
}
class AdditionalFee {
#Id
private int id;
//other fields, getters, setters..
}
and additionalFees was the field causing the problem.
What I was missing and what helped me are the following:
#Entity annotation on the generic type argument (AdditionalFee) class;
#OneToMany (or any other type of association that fits particular business case) annotation on the private List<AdditionalFee> additionalFees; field.
So, the working version looked like this:
#Entity
public class SomeFee {
#Id
private Long id;
#OneToMany
private List<AdditionalFee> additionalFees;
//other fields, getters, setters..
}
#Entity
class AdditionalFee {
#Id
private int id;
//other fields, getters, setters..
}
Change #basic to #OneToMany for List types
Or you can mark it as #Transient if it doesn't exist on DB table.
#Transient
private List<String> authorities = new ArrayList<>();
As the message says, #Basic should not be used for containers (e.g. Java collections). It is only to be used for a limited list of basic types. Remove the #Basic annotation on that field.
If, as you say in the question, the error message is still there, you might need to try the following steps in order:
Save the file
Close and reopen the file
Clean and rebuild the project
Restart the IDE
(these are generic steps, which I use when an IDE is generating a compilation error that obviously makes no sense.)
This can also happen when your class is missing its #Entity annotation. When you get weird warnings like these, sometimes it helps to try and compile and see if the compiler complains.
The error seems not have impact on GAE since I can run the app and store data into storage. I guess it's a bug in IntelliJ IDEA and you can simply ignore it.
'Basic' attribute type should not be a container
This error occurs when you declare an existing entity as an attribute in the current Entity without declaring the relationship type which could be either of the JPA relationships.
Detailed Article on JPA relationships
I am attempting to implement a Hibernate/JPA2 solution over an existing schema, which cannot be changed. Here is a minimal example of the existing schema:
CREATE TABLE REASON (
REASON_CODE CHAR(1),
REASON_DESCRIPTION CHAR(50))
CREATE TABLE HEADER (
REASON_CODE CHAR(1),
OTHERFIELD1 CHAR(40),
OTHERFIELD2 CHAR(40) )
Normally this would be the "correct" way from a DB perspective: Link REASON to HEADER by the REASON_CODE. However it's presenting me with an awkward problem in Java and I'm not sure of the best way to solve it. I've modeled these entities as follows:
#Entity
#Table(name="REASON")
public class Reason implements java.io.Serializable {
#Id
#Column(name="REASON_CODE", unique=true, nullable=false, length=1)
private Character reasonCode;
#Column(name="REASON_DESCRIPTION", nullable=false, length=25)
private String reasonDescription;
}
#Entity
#Table(name="HEADER")
public class Header implements java.io.Serializable {
#ManyToOne
#JoinColumn(name = "REASON_CODE", nullable = false)
private Reason reason;
#Column(name="OTHERFIELD1")
private String otherField1;
#Column(name="OTHERFIELD2")
private String otherField2;
}
Once again, as far as I can tell, this is "correct" from a Java perspective - linking Header to Reason with a reference.
The problem is that when I need to use one of these Reason values in my code I wind up with awkward syntax like:
Reason r = reasonService.findOne('X'); // X is the REASON_CODE in the database record
// Do some processing with variable r
Or this:
header.setReason(reasonService.findOne('X'));
Ideally I could implement Reason as an enum like:
public enum Reason {
X_MARKSTHESPOT("X"),
C_MEANSSOMETHINGELSE("C"),
F_MEANSATHIRDTHING("F") ;
private String code;
private Reason(String code) {
this.code = code;
}
}
And then simply have this in my code:
header.setReason(Reason.X_MARKSTHESPOT);
But from what I understand that is not possible with JPA, which offers only EnumType.STRING (basically the name) or EnumType.ORDINAL (even worse, the index in the enum list). A possible way around this would be JPA 2.1's Converter, but I have never used it. I have also read here (in one of the answers) that a Hibernate User Type might be useful. One of our programmers has solved this in another app by writing two complete classes - an enum class for internal use and a "shadow" class which iterates through the enum and syncs the records in the database on every startup. But this seems like a kludgey way to do it. What is the best way to handle this, bearing in mind that the database schema cannot be changed?
I'm developing an Java-application which stores its data via Hibernate in a database.
One feature of this application is to define templates like types, etc. for reuse. For instance the type has attributes and you can create instances of an type, which has values for the attributes.
The problem is, that I don't know how to ensure that only values for attributes can assigned which the type defines. In my solution there is a redundancy which cause the problem, but I don't know how to remove it.
My current (and problematic) approach looks like this:
#Entity
class Type
{
#Id
#Generated
private Long id;
#OneToMany(mappedBy="type")
private List<Attribute> attributes;
//...
}
#Entity
class Attribute
{
#Id
#Generated
private Long id;
#ManyToOne
private Type type;
//...
}
#Entity
class Instance
{
#Id
#Generated
private Long id;
#ManyToOne
private Type type;
//...
}
#Entity
class AttributeValue
{
#Id
#Embedded
private ResourceAttributValueId id;
#Column(name="val")
private String value;
//...
}
#Embeddable
public class ResourceAttributValueId implements Serializable
{
#ManyToOne
private ResourceStateImpl resource;
#ManyToOne
private ResourceAttributeImpl attribute;
//...
}
There the definition of the type is redundant: Type can be reached via AttributeValue->Attribute->Type and AttributeValue->Instance->Type
Another idea was to use type + attribute name as id of the attribute and instance + attribute name as id of the attribute value, but that doesn't solves my problem.
The key for correctly modeling "diamond-shaped" dependencies like this is the usage of identifying relationships:
(I took a liberty of renaming your entities slightly, to what I believe is a more consistent naming scheme.)
Note how we migrate the TYPE_ID from the top of the diamond, down both sides, all the way to the bottom and then merge it there. So, since there is only one ATTRIBUTE_INSTANCE.TYPE_ID field and is involved in both FKs, we can never have an attribute instance whose attribute type's type differs from instance's type.
While this avoids "mismatched" attributes, it still doesn't ensure the presence of attribute instances (if you support the concept of "required attribute"), which is best enforced at the application level. Theoretically you could enforce it at the database level, using circular deferred FKs, but not all DBMSes support that, and I doubt it would play nicely with ORMs.
Unfortunately, I'm not experienced enough with Hibernate to answer whether this can be mapped there and how.
See also:
Choosing from multiple candidate keys
How to keep foreign key relations consistent in a “diamond-shaped” system of relationships
What is appropriate way of creating objects with One-to-Many relationship using Objectify and RequestFactory? I've read documentation for these libraries, and also reviewed number of sample projects such as listwidget and gwtgae2011. All of them use #Embedded annotation which is not what I want because it stores everything within one entity. Another option according to documentation would be to use #Parent property in child classes. In my example (getters/setters removed for simplicity) I have entities Person and Organization which defined as
#Entity
public class Person extends DatastoreObject
{
private String name;
private String phoneNumber;
private String email;
#Parent private Key<Organization> organizationKey;
}
and
#Entity
public class Organization extends DatastoreObject
{
private String name;
private List<Person> contactPeople;
private String address;
}
Now if I understood documentation correctly in order to persist Organization with one Person I have to persist Organization first, then set organizationKey to ObjectifyService.factory().getKey(organization) for Person object and then persist it. I already don't like that I have to iterate through every child object manually but using RequestFactory makes everything is more convoluted due to presence of proxy classes. How would I define Organization and OrganizationProxy classes - with Key<> or without it ? Will I have to define something like this in Organization ?
public void setContactPeople(List<Person> contactPeople)
{
for (int i = 0; i < contactPeople.size(); ++i)
{
DAOBase dao = new DAOBase();
Key<Organization> key = dao.ofy().put(this);
contactPeople.get(i).setOrganizationKey(key);
}
this.contactPeople = contactPeople;
}
And how would I load Organization with its children from Datastore ? Will I have to manually fetch every Person and fill out Organization.contactPeople in #PostLoad method ?
It seems like I'll have to write A LOT of maintenance code just to do what JPA/JDO does behind the scene. I simply don't get it :(
Am I missing something or it's the only way to implement it ?
Thanks a lot for answers in advance!!!
You need to make it as #Parent only when you going to use it in transaction against all Person in this Organization. I'm sure it's not what you want.
It's enough to save just private Key<Organization> organizationKey, and filter by this field when you need to find Person for specified Organization
As about loading all referenced objects - yes, it is, you have to load it manually. It's pita, but it's not a lot of code.
Also, there is a different way to store this relationship, if your organization are small enough, and consists of few hundreds of people. At this case you can have List<Key<Person>> contactPeopleKey;, and load all this people by existing Key, manually, it much be much faster than loading by new Query