How to get an entity that has parent reference? - java

In my Spring project and using Google App Engine, I'm trying to get an entity from datastore, but in this case this entity has a #Parent relation. I only have the id from the entity, a this point unaware information about Parent relation.
I tried different querys, using ancestor filterKey, at this moment I have this:
#Override
public House getNotRestrictions(Long id){
return objectifyService.ofy().load().type(House.class).filterKey(Key.create(House.class, id)).first().now();
}
My model is something like this:
#Entity
public class House {
#Id
public Long id;
//other attributes
#Index
#Parent
public Key<User> createdBy;
//methods getter and setters
}
When I execute the query, it returns to me and null entity. But the id into the datastore exists.

Every entity has a key that includes its kind, ID/name, and kind + ID/name of all of its ancestors. If you create a key without passing ancestor information, this key will be different from the entity you are trying to retrieve.
Also note that you can have many entities with the same kind and ID, if they have different parents.

There are only two ways:
//1. creating the full key with parent:
Key<House> houseKey = Key.create(Key.create(User.class, userId), House.class, id);
//2. or using the webSafeString key representation which contains the whole key path including namespace and parents:
String webSafeKey = "<encoded key as string>";
Key<House> houseKey = Key.<House>create(webSafe)
//Then you can fetch the entity:
House house = ofy().load().key(houseKey).now();
Since you mentioned you don't know the parent. You could start using the webSafeString instead - see Key.toWebSafeString() method

Related

How to create an entity object in Spring Boot when the entire table is the key?

I'm creating an entity object that I will use to query a database with. However, I'm not sure how to build it since all of the columns are the key for the table. Typically I'd create an Entity object with the parameters that aren't the key and make a nested object within that one as the key. That entity object key would hold the values needed to build the key. But, in this case, all 5 values of the table are used for the key.
This is what I have currently, but I know that it's wrong.
Would I just have to make an #EmbeddedId key object within this one and push all of the values to that while practically leaving this base entity object empty? Or is there a better way to do this?
#Entity
#Table(name = "<insert>", schema="<insert>")
public class Market {
#Id
#Column(name="MKT_ID")
private String marketId;
#Column(name="DLR_CD")
private String dealerCd;
#Column(name="SER_NO_PFX")
private String serialNoPrefix;
#Column(name="SER_NO_BDY")
private String serialNoBody;
#Column(name="USER_ID")
private String userId;
}

How to join Hibernate?

public class Primary{
private long id;
#Id
#GeneratedValue(
strategy = GenerationType.IDENTITY
)
#Column(
name = "id"
)
public void getId(){return id;}
//other vars
}
public class Secondary{
//other vars
private Primary primary;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "primary_id", unique = true)
public Primary getPrimary(){return primary;}
}
From this, it is pretty easy to get a Primary Object from a Secondary Object. However, how do I get Secondary Object from a Primary Object without selecting twice in Hibernate?
The Primary class should look like this:
#OneToMany(mappedBy="primary", cascade={CascadeType.ALL})
private List<Secondary> secondaries;
// getter and setter
And you should make a small modification in Secondary:
#JoinColumn(name = "id", unique = true)
public Primary getPrimary(){return primary;}
Cause join column should refer to the joined field(id) in Primary.
The answer could be quite different based on what you are looking for.
Based on your current mapping, assuming you have a Primary instance on hand, you can get its corresponding Secondary by querying. E.g. by HQL:
from Secondary s where s.primary = :primary
and pass in your primary as the parameter.
If you are looking for way to navigate from a Primary object instance, you could have created a bi-directional mapping:
class Primary {
#OneToMany(mappedBy="primary", ...)
private Set<Secondary> secondaries;
}
class Secondary {
#ManyToOne
private Primary primary;
}
You could refer to my (very old) answer on related question on how to define it. https://stackoverflow.com/a/13812047/395202
However, simply having a bi-directional relationship DOES NOT avoid "selecting twice", if your "selecting twice" means running 2 SQL queries in DB.
To reduce such round-trip, there are several way to solve. First one is to declare the relationship as EAGER fetch. However this is a way that I don't usually recommend so I won't go deeper.
Another (imho, more appropriate) way is to do a join fetch when you are fetching Primary. To fetch the Primary instance with its related Secondary instances, use a HQL like :
from Primary p left join fetch p.secondaries where ....
Add this Setter method in the Secondary Class
public Primary getPrimary() {
return primary;
}
And get the primary object from Secondary Class

Criteria API createAlias on column containing null values kills the query

I do have a simple entity named "Address" that has a couple of properties and relations defined by itself and some inherited from some superclass.
public class Base {
private UUID id;
private Date createdAt;
#NotNull
private User createdBy; // User is a related Entity that cannot be null
private DataImport dataImport; // DataImport is another related entity that can be null
//getter & setter
}
public class Address extends Base {
private String street;
#NotNull
private Country country; // related entity that can't be null
//getter & setter
}
What I'm trying to achieve is with one query using the Criteria API, I want to get a list of Address objects containing all simple attributes like street and createdAt. At the same time I want only the IDs of the related entities if present: createdBy.id, dataImport.id and country.id.
I'm almost there using the following Criteria query:
entityManager.getDelegate().createCriteria(Address.class).add(criteriaExample)
.excludeZeroes()
.createAlias("createdBy", "subcreatedBy")
.createAlias("country", "subcountry")
.setProjection(Projections.projectionList().add(Projections.property("id").as("id"))
.add(Projections.property("createdAt").as("createdAt"))
.add(Projections.property("street").as("street")).
.add(Projections.property("subcreatedBy.id").as("createdBy.id"))
.add(Projections.property("subcountry.id").as("country.id")))
.setResultTransformer(new AliasToBeanNestedResultTransformer(Address.class));
List<Address> result = criteria.list();
This works just perfect!
Problem occurs when I only add the "alias" for the dataImport relation.
...createAlias("dataImport", "subdataImport")...
Even without adding the Projection for dataImport.id to the query, it returns an empty list, meaning list.size() = 0, as soon as I add this alias.
My current guess is, that I can't put an alias on a nullable property. Does anybody have an idea what the solution might be? So, when the related entity is not null, I want to get it's ID. And I want it to be simply null, when the relation is not set.
Thanks in advance.
Stupid me should have read the documentation and set the CriteriaSpecification.LEFT_JOIN.
...createAlias("dataImport", "subdataImport", CriteriaSpecification.LEFT_JOIN)...

Do I use the correct JPA annotations for persisting my entities in my H2 database?

my problem:
#Entity
public class Container {
#OneToMany(cascade = CascadeType.ALL)
private List<Element> containedElements;
public final List<Element> getContainedElements() {
return containedElements;
}
}
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Element {
#ManyToOne(cascade = CascadeType.ALL)
private Container myContainer;
public final Container getMyContainer() {
return myContainer;
}
public abstract Object getValue();
public abstract void setValue(final Object newValue);
}
#Entity
public class StringElement extends Element {
private String someValue;
public final Object getValue() {
return someValue;
}
public final void setValue(final Object newValue) {
someValue = newValue;
}
}
I have a container class containing probably many objects of an abstract class Element.
I have more than one implementation of this Element class, one of them StringElement.
Using the JPA API (provided by Hibernate) and a local H2 database and a small test class, I can persist entities of these classes and query the database for them and output them to the console.
Using Wildfly 8.0 (JBoss), the JPA API (provided by Hibernate) and a Wildfly-"managed" H2 database, I can persist entities, but when I query the database for a Container object, I cannot access the contained elements. Trying to do this results in the following error:
Caused by: java.lang.NumberFormatException: empty String
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1011)
at java.lang.Double.parseDouble(Double.java:540)
at org.h2.value.Value.convertTo(Value.java:846)
I can query the database for a list of all StringElements in the database and parse the results. I can access the Container via getMyContainer(). Then when I try to access an Element via getContainedElements().get(0), I get the above error again.
Did I use the correct JPA annotations? How can I have a list of abstract objects in my container?
#OneToMany annotation has FetchType.LAZY as default.
It looks like you are trying access containedElements when the Container entity is no longer managed by the persistence context.
You must read containedElements when the Container is managed by persistence context (if you want to leave FetchType.LAZY) or just change fetch to FetchType.EAGER:
#OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER )
private List<Element> containedElements;
I can finally answer this on my own:
The problem lies with multiple classes that inherit Element. Or rather, the cause of the error are two or more classes inheriting from Element which each have an attribute named someValue. The problem is that each attribute has a different primitive type.
Doing a select over all Elements (and subclasses of it) tries to join the tables of two Element subclasses and then tries to merge the someValue columns. As each column has a different type, the engine gives the merged column some type (e.g. Long) and tries to cast all values from the other columns to the decided type.
One DB engine merged the columns and made a Long column. This resulted in the above error. Another DB engine merged the columns and made a Varchar column. This resulted in no error because all my values could be easily transformed to Varchar.

Cascade soft-delete with #MappedSuperclass in hibernate

I am working on a huge application with a complex database schema. I am using Spring and Hibernate for the development.
I wanted to know how to soft-delete an entity(where the active field is there in a superclass rather than having in all the entities). I implemented the suggestion provided here.
Below is the structure of my entities and hibernate util classes
Base Entity
#MappedSuperclass
public abstract class BaseEntity<TId extends Serializable> implements IEntity<TId> {
#Basic
#Column(name = "IsActive")
protected boolean isActive;
public Boolean getIsActive() {
return isActive;
}
public void setIsActive(Boolean isActive) {
isActive= isActive;
}
}
Child Entity :
#Entity(name="Role")
#Table(schema = "dbo")
public class Role extends BaseEntity {
//remaining fields
//1. foreign key reference to another entity
//2. List<Child> entities
//3. Self reference fields
}
Hibernate Util Class:
public void remove(TEntity entity) {
//Note: Enterprise data should be never removed.
entity.setIsActive(false);
sessionFactory.getCurrentSession().update(entity);
}
Now I have a few requirements with this which I am not able to solve now.
When I delete 'Role' entity, all the children entities should also get deleted (soft delete only for all) :-> Do I need to fetch the parent entity, iterate through the children and delete one by one ?
Role has a foreign-key reference with another entity 'Department'. If a department is deleted, the roles associated should get deleted conditionally(ie, only if the caller decides: in some cases, we dont want to delete the referred entities).
There are some self-referencing column like 'ParentRoleId'. If a Role is deleted, all its referenced roles also should be deleted. -> Do I need to fetch the ID and then delete all the self-referenced children entities and then delete each?
eg: Department can have a parent department(which is by using the field : parentdeptid). If I delete a parent department, all the sub-departments should get deleted
If anyone has any suggestions on how to do this, please let me know.

Categories