Hibernate - how to load different view of same object - java

How is this called and how to solve my next problem on API. I have to return same object with different views. Some data should not be returned to user. Here is example:
Parent:
public class OrginalObject{
private int id;
private String name;
private String surname;
private int age;
private String school;
private String secret;
private Address Address;
child:
public class Address{
private int id;
private String street;
private String zipCode;
private String Country;
If i want to load list of complete objects i would call:
session.createCriteria(OrginalObject.class).list();
1.) But if don't want someone to know my property secret, i need to hide it. But i don't know how to call it from database the way it would have every other property. Something like:
session.createCriteria(OrginalObjectPublic.class).list();
2.) Also I would like to have option to load only "important" data. That means only properties id, name, school.
session.createCriteria(OrginalObjectImportant.class).list();
Is there a way to do an adapter/"custom view" to directly load it from database? I know i can write pure sql, but i would like to use it on objects with 20+ properties that have nested lists/objects.
3.) Also how to use this transformation to load only few properties of nested object with those from orginal. Example json (only id, name, school from OrginalOBject and id, street from Address:
{
"id": 1,
"name": "testname",
"school": "testschool",
"Address": {
{
"id": 33,
"street": "testStreet 33"
}
}
4.) also how to use it on nested Lists if Address would be array:
public class OrginalObject{
...
private List<Address> AddressList;

Since hibernate is a persistence-framework and you can not save/persist to a view, this is not possible. Yes you can make a view having the name like the table and preferr the view but you will not be able to store to that entity anymore.
You can remove the getter (getSecret) from the entity. So the database still have the field but your entity is not aware of it. This may cause problems if you try to store data using that entity, you may not be able to set the secret.
You can make the getter default (package-level-access) and seal the package to let noone else than the sealed projects access the getter.
You can use spring's method authorization mechanism

First no one have access to your secret,
only you the programmer who is supposed to see it.
Second if no one is supposed to have it why store it.
And if you want to pull it out you can use inheritance.
something like
public abstract PublicObject {
...
}
public OriginalObject extends PublicObject {
String secret;
}
Edit:
2nd & 4th questions you can solve them with hql:
String hql = "SELECT O.id, O.name, O.school FROM OrginalObject O";
Query query = session.createQuery(hql);
List results = query.list();
as for your 3th question it depends on your api. if you're using jackson for example you can use #JsonIgnore

You can map more than one entity to the same table, each one with the set of properties you want to expose.
Take a look to this question.

Related

When all columns of an #Embedded field are NULL (JPA / Hibernate) - how to prevent null pointer?

Is there any way to init a empty object, even if all values are null?
#Embeddable
public class Address {
private String street;
private String postalCode;
private String city;
}
#Entity
public class Person {
#Embedded
private final Address home = new Address();
}
The problem is, when you hydrate a Person, if all fields of the embedded Address are null, it seems like hibernate is initializing home to null.
It is not initializing it as a "new Address()".
Is there any way to force hibernate to initialize home as "new Address()" even with all fields null?
Trying to avoid things like:
public Address getHome(){
if(home == null){
this.home = new Address();
}
return this.home;
}
You can control this with the hibernate.create_empty_composites.enabled configuration which you can read about in the documentation: https://docs.jboss.org/hibernate/orm/5.6/userguide/html_single/Hibernate_User_Guide.html#_misc_options
If this is your only code, then there is nothing here that will produce a NPE. If you are calling something like getHome().getStreet().length() then it will if the field street was set to null based on the results of the query. This is the correct behavior, and you shouldn't attempt to change it. This way it's up to you to write your code in a manner that's null-safe.
If you still just want to have these fields as an empty String rather than Null, then you can create a custom type in Hibernate. Implement org.hibernate.usertype.UserType, in the nullSafeGet and nullSafeSet methods, you'll return an empty String in place of any null values. Then you'd simply annotate your fields with #Type()
#Type(type = "com.acme.MyCustomType")
private String street;
Again, I would highly recommend AGAINST taking this approach as you're going to end up with more headaches than just dealing with NPEs

How to map a List<ObjectDTO> to Entity inside of a Bean with Model Mapper?

I have a 1:N relationship where a Victim might have lots of EmergencyContacts.
I've created a DTO called VictimDTO and inside of it there's a List and I'm using ModelMapper to convert my DTO into an Entity.
When I get rid of the list just for testing purposes, it works fine placing this code snippet inside of the insert "POST" method in the Controller layer in Java:
VictimEntity victimEntity = modelMapper.map(victimDTO, VictimEntity.class);
But now I've placed this List inside of my VictimDTO and I'm getting an Exception when trying to use this code.
My DTO actual code is this one as it follows below:
public class VictimDTO {
private String name;
private int age;
private String email;
private String phone;
private List<ContactDTO> contactDTOList;
//getters and setters
}
How can I use ModelMapper to convert a POJO with a Collection (List) as an instance variable inside into an Entity?
Thank you for your help.
Best regards,
Lucas AbrĂ£o

GAE Endpoints (Java) with objectify - how to model partial data (for client)?

I have the following entities:
#Entity
public class Person {
#Id public Long id;
public String name;
public Ref<Picture> picture;
public String email;
public byte age;
public short birthday; // day of year
public String school;
public String very_long_life_story;
... some extra fields ...
}
#Entity
public class Place {
#Id public Long id;
public String name;
public String comment;
public long createdDateMS;
public long visitors;
#Load public List<Ref<Person>> owners;
}
Few notes:
(A) Maximum size of owners, in Place entity, is 4 (~)
(B) The person class is presumable very big, and when querying place, I would like to only show a subset of the person data. This optimizations is aimed both at server-client and server-database communications. Since objectify (gae actually) only load/save entire entities, I would like to do the following:
#Entity
pubilc class PersonShort {
#Id public Long id;
public Ref<Picture> picture;
public String name;
}
and inside Place, I would like to have (instead of owners):
#Load public List<PersonShort> owners;
(C) The problem with this approach, is that now I have a duplication inside the datastore.
Although this isn't such a bad thing, the real problem is when a Person will try to save a new picture, or change name; I will not only have to update it in his Person class,
but also search for every Place that has a PersonShort with same id, and update that.
(D) So the question is, is there any solution? Or am I simply forced to select between the options?
(1) Loading multiple Person class, which are big, when all I need is some really small information about it.
(2) Data duplication with many writes
If so, which one is better (Currently, I believe it's 1)?
EDIT
What about loading the entire class (1), but sending only part of it?
#Entity
public class Person {
#Id public Long id;
public String name;
public Ref<Picture> picture;
public String email;
public byte age;
public short birthday; // day of year
public String school;
public String very_long_life_story;
... some extra fields ...
}
public class PersonShort {
public long id;
public String name;
}
#Entity
public class Place {
#Id public Long id;
public String name;
public String comment;
public long createdDateMS;
public long visitors;
// Ignore saving to datastore
#Ignore
public List<PersonShort> owners;
// Do not serialize when sending to client
#ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
#Load public List<Ref<Person>> ownersRef;
#OnLoad private void loadOwners() {
owners = new List<PersonShort>();
for (Ref<Person> r : ownersRef) {
owners.add(nwe PersonShort(r.get()));
}
}
}
It sounds like you are optimizing prematurely. Do you know you have a performance issue?
Unless you're talking about hundreds of K, don't worry about the size of your Person object in advance. There is no practical value in hiding a few extra fields unless the size is severe - and in that case, you should extract the big fields into some sort of meaningful entity (PersonPicture or whatnot).
No definite answer, but some suggestions to look at:
Lifecycle callbacks.
When you put your Person entity, you can have an #OnSave handler to automatically store your new PersonShort entity. This has the advantage of being transparent to the caller, but obviously you are still dealing with 2 entity writes instead of 1.
You may also find you are having to fetch two entities too; initially you may fetch the PersonShort and then later need some of the detail in the corresponding Person. Remember Objectify's caching can reduce your trips to Datastore: it's arguably better to have a bigger, cached, entity than two separate entities (meaning two RPCs).
Store your core properties (the ones in PersonShort) as separate properties in your Person class and then have the extended properties as a single JSON string which you can deserialize with Gson.
This has the advantage that you are not duplicating properties, but the disadvantage is that anything you want to be able to search on cannot be in the JSON blob.
Projection Queries. You can tell Datastore to return only certain properties from your entities. The problem with this method is that you can only return indexed properties, so you will probably find you need too many indexes for this to be viable.
Also, use #Load annotations with care. For example, in your Place class, think whether you really need all those owners' Person details when you fetch the owners. Perhaps you only need one of them? i.e., instead of getting a Place and 4 Persons every time you fetch a Place, maybe you are better off just loading the required Person(s) when you need them? (It will depend on your application.)
It is a good practice to return a different entity to your client than the one you get from your database. So you could create a ShortPerson or something that is only used as a return object in your REST endpoints. It will accept a Person in its constructor and fill in the properties you want to return to the client from this more complete object.
The advantage of this approach is actually less about optimization and more that your server models will change over time, but that change can be completely independent of your API. Also, you choose which data is publicly accessible, which is what you are trying to do.
As for the optimization between db and server, I wouldn't worry about it until it is an issue.

How to make a java class related to another class with Neo4j?

I have a class House and a class Room. Each of these classes are a NodeEntity and are persisted in separate repositories, HouseRepository and RoomRepository. House contains a Set<Room>. I want to be able to delete a Room instance and automatically have that instance removed from the Set<Room> inside of the House class. Since Neo4j is a graph database, I figured that I should be able to declare a relationship between the House and each Room and deleting a Room instance will take care of this automatically. The two following classes represent House and Room.
#NodeEntity
public class House {
#GraphId
private Long id;
#Indexed(unique=true) String uid;
#RelatedTo (type="addition", direction=Direction.OUTGOING)
#Fetch
private Set<Room> rooms;
public House(String uid, Set<Room> rooms) {
this.uid = uid;
this.rooms = rooms;
}
public House() {
this.uid = //random uid;
}
}
#NodeEntity
public class Room {
#GraphId
private Long id;
#Indexed(unique=true) String uid;
public Room(String uid) {
this.uid = uid;
}
public Room() {
this.uid = //random uid;
}
}
I am thinking that I should be able to write a Cypher query in the RoomRepository that would take care of this, but I am not sure. I have thought of something like this:
public interface RoomRepository extends BaseRepository<Room>{
#Query("start room=node({0}) " +
"match house-[:addition*]->room" +
"delete room")
public void deleteRoomAndRemoveRoomFromHouse(String uid);
}
What is the recommended way to handle these types of deletes?
Your approach should almost work. You may bump up against an exception because you try to delete a node without first having deleted its relationship. (Unless SDN magic takes care of that for you, but I don't think it intercepts cypher queries.)
As your MATCH clause stands, it will act as a filter, meaning that whatever is bound to the room identifier in your start clause is only retained by the time you reach the delete clause if it has the relevant relationship of at least depth 1. If the room you pass as a parameter does not have at least one incoming [:addition] relationship, it is no longer bound and won't be deleted. Perhaps this is intentional, if so keep it, but add (otherwise replace it with) a match clause that binds all the rooms relationships and deletes them before you delete the room. Try something like
START room=node({0})
MATCH room-[r]-()
DELETE r, room
But I think either the repository or Neo4jTemplate should have plenty of voodoo to take care of this kind of operation for you. Or if you use the advanced mapping with AspectJ, you may have all kinds of chocolate chips baked into your room entity. I know there is a NodeEntity#persist(), I think there is a NodeEntity#remove() as well.
Once the node is deleted, it won't show up in the Set<Room> field of your room class. (If you use simple mapping you may have to retrieve it or sync it manually to the database, possibly a Neo4jTemplate#fetch(), passing the Set<Room> field, will do that for you.)

Hibernate sort by properties of inner bean?

In my domain model I have following Classes.A 'UserProfile' has one 'SecurityPrincipal'
class SecurityPrincipal{
private String loginId;
private String password;
private Date registeredData;
private int status;
}
class UserProfile {
private String name;
private String company;
private SecurityPrincipa principal
}
I want to get the sorted results of 'UserProfile' objects and it works fine for simple properties.Like
DetachedCriteria criteria=DetachedCriteria.forClass(UserProfile.class);
criteria.addOrder(Order.asc("name");
But when I try to access properties of inner bean (SecurityPrincipal instance) like
criteria.addOrder(Order.asc("principal.status");
Hibernate gives the error:
Caused by:
org.hibernate.QueryException: could
not resolve property:
securityPrincipal.status of:
com.bigg.ibmd.usermanagement.model.UserProfile
at
org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:44)
at
org.hibernate.persister.entity.AbstractPropertyMapping.toColumns(AbstractPropertyMapping.java:59)
at
org.hibernate.persister.entity.BasicEntityPropertyMapping.toColumns(BasicEntityPropertyMapping.java:31)
How can I sort my results by properties-of-a-property?
Thanks
Try this:
DetachedCriteria criteria=DetachedCriteria.forClass(UserProfile.class);
criteria.createAlias("principal", "p");
criteria.addOrder(Order.asc("p.name"));
I haven't tried it, nor am I sure that it's the nicest way, but I think it should work.
For filtering by multiple fields you ought to use #OrderBy annotation. For example:
#OrderBy("id, name, whatever")
private SecurityPrincipa principal
...
Pay attention JPA Criteria api 2.0 generates OUTER JOIN for collections. It means if you have not One to One but One to Many relation in the table it fetchs multiple results:
#OrderBy("weight, height")
private Collection userVitalStatsCollection;
To avoid duplicates it is handy to use Database View.

Categories

Resources