Objectify Google DataSore Query - java

Here's the thing :-)
We have two classes, Appointment and Hairdresser, both having the same, one ancestor (a static final Key: topParent) representing the HairSalon Key. The Appointment contains the Hairdresser like this:
#Parent
public Key parent;
public Key hairdresserKey;`
but when we try to filter out the appointment, it doesn't come up with a result. The parent in the hairdresserKey == null, that might be a clue, but we're kind of stuck now.
So can someone please tell us what's wrong with this query?
Thanks a lot!
appointment.hairdresserKey = new Key<Hairdresser>(topParent, Hairdresser.class, appointment.hairdresser.id);
appointment.parent = topParent;
Key<Hairdresser> queryKey = new Key<Hairdresser>(topParent, Hairdresser.class, appointment.hairdresser.id);
Objectify ofyTransaction = ObjectifyService.beginTransaction();
try {
List<Key<Appointment>> previousTimeSlotOneHour = ofyTransaction.query(Appointment.class)
.ancestor(topParent)
.filter("hairdresserKey", appointment.hairdresserKey)
.filter("timeSlot", appointment.timeSlot.getPreviousTimeSlot())
.filter("LENGTH", 1.0d).listKeys();
To clearify some more, this is how Appointment set up:
#Unindexed
public class Appointment implements Serializable {
#Id
public Long id;
#Indexed
public TimeSlot timeSlot;
#Transient
public WorkDay workDay;
#Transient
public Customer customer;
public Key customerKey;
public int END_TIME_HOUR;
public int END_TIME_MINUTES;
#Indexed
public TREATMENT treatment = TREATMENT.TREATMENT_CUT;
public int revisionNumber = -1;
/* QUERY Fields */
#Indexed
private String stringDate;
private double LENGTH;
#Parent
public Key parent;
private Date date;
#Transient
public Hairdresser hairdresser;
public Key hairdresserKey;

Found this:
This is almost certainly an indexing issue. In order for that query to work, you must define two indexes:
A single-property index on referenceKeyToC
A multi-property index on {ancestor, referenceKeyToC}
In Objectify 3.x, properties have single-property indexes by default, but if you have added #Unindexed to the class B then you need to put #Indexed on referenceKeyToC.
The multi-property index is defined in datastore-indexes.xml. If you run this query in dev mode, the environment should provide you with the snippet of xml needed.
That did the trick! Thanks for pointing in the right direction!

Related

Hibernate many-to-many set primary/foreign keys in thrid table

I have 3 java classes, two entites and the third is relationship between them. I want to map them in hbm.xml, but I don't know how, I can't find any example on internet
public class Product {
private String _description;
private String _name;
private double _price;
private Long _productId;
private int _quantity;
public class Order {
private Long _orderId;
private List<OrderProduct> _productList;
private User _user;
public class OrderProduct {
private Order _order;
private Product _product;
How to map this in xml, to this thrid class "OrderProduct" stores only order and product as primary and foreign keys.
Thanks in advice
There is no need for OrderProduct entity. You can define the mapping in the hbm Itself. Please see the below link to understand how its done.
https://www.mkyong.com/hibernate/hibernate-many-to-many-relationship-example/

Hibernate Inheritance mapping issue

So, after several attempts of trying and trying to make this work the way I want, and of course checking different guide, I now come to you guys.
My program is designed to work like this:
persona (the father object)
-persona_cuil (pk on DB, generated by user)
empleado (persona's son)
-legajo_id (pk on DB, generated by program NOT DB (couldnt make that work either))
-persona_cuil (FK from persona)
empvarios (empleado's son)
-legajo_id (PK and FK from empleado)
Now, the database is mapped that way, and it works just fine, the problem seems to be that hibernate somewhere mixes the primary keys sent to each object, and instead of inserting a legajo_id in empvarios, it inserts a persona_cuil.
Code for clases:
persona:
#Entity
#Table(name = "persona")
#Inheritance(strategy = InheritanceType.JOINED)
public class persona implements Serializable {
private static final long serialVersionUID = 2847733720742959767L;
#Id
#Column(name="persona_cuil")
private String persona_cuil;
#Column(name="nombre")
private String nombre;
#Column(name="apellido")
private String apellido;
#Column(name="fecha_nac")
private String fecha_nac;
#Column(name="direccion")
private String direccion;
#Column(name="localidad")
private String localidad;
#Column(name="provincia")
private String provincia;
#Column(name="pais")
private String pais;
#Column(name="fecha_muerte")
private String fecha_muerte;
#Column(name="fecha_alta")
private String fecha_alta;
#Column(name="fecha_baja")
private String fecha_baja;
#Column(name="mail")
private String mail;
#Column(name="plan_id")
private int plan_id;
public persona (){
this.setPlan_id(0);
}
//Getters and Setters
}
empleado:
#Entity
#Table(name = "empleado")
#Inheritance(strategy = InheritanceType.JOINED)
#PrimaryKeyJoinColumn(name="persona_cuil")
public class empleado extends persona implements Serializable {
private static final long serialVersionUID = -7792000781951823557L;
#Column(name="legajo_id")
private int legajo_id;
public empleado(){
super();
int leg = SentenceManager.ultimoRegistro("empleado");
if (leg == 0){ //this works fine, it just searches the last registry, if it exists, i uses the next available number
this.setLegajo_id(1);
}
else {
this.setLegajo_id(leg+1);
}
}
//Getters and Setters
}
empvarios:
#Entity
#Table(name="empvarios")
#PrimaryKeyJoinColumn(name="legajo_id")
public class empvarios extends empleado implements Serializable, ToPersona{
private static final long serialVersionUID = -6327388765162454657L;
#Column(name="ocupacion_id")
int ocupacion_id;
public empvarios() {
super();
this.setLegajo_id(super.getLegajo_id());
}
//Getters and setters
}
Now, if I try to insert a new empleado into the database, it works just fine... BUT if I try to insert an empvarios, in the place where should be legajo_id, hibernate places the persona_cuil (I tested this by removing the FK restriction on the data base)
Images below:
(cant post images due reputation restriction :/)
https://www.dropbox.com/sh/mu5c797adlf7jiv/AACnd8mx7GriSyq5OMKoddRna?dl=0
There you have the 3 photos, the name of the files shows which table is each one.
Any ideas on whats going on?
The problem was that the data base was wrongly mapped.
If anyone has this problem then you will have to rethink the structure of the DB.
As seen in the example i gave above, the database should look like this:
persona:
persona_id (PK-autoincemental)
empleado:
persona_id (FK to persona)
legajo_id
empvarios:
persona_id (FK to persona)
ocupacion_id
The reason this works like this is because you cannot have different ids to depend different clases within the data base. On the program side it "can" work like that, but it the data base it has to be mapped differently.
Thanks!

index not updating after external entity changes

I'm currently working on a project to persist data with JPA 2.1 and to search entities using hibernate search 4.5.0.final.
After mapping classes and indexing, the searching works fine.
However, when I changed the value description of classB from "someStr" to "anotherStr". The database was updated accordingly, but when I checked the index using Luke, classA.classB.description in the index wasn't updated, and the data cannot be searchable by keyword "anotherStr", but can be searchable by keyword "someStr".
After I reindex the whole database, it's updated finally.
According to Hibernate search website,
The short answer is that indexing is automatic: Hibernate Search will transparently index every entity persisted, updated or removed through Hibernate ORM. Its mission is to keep the index and your database in sync, allowing you to forget about this problem.
But it's not working in my case. I'm not sure if I missed some details or I need to handle it myself for this kind of issues.
I also tried to add annotation #Indexed on classB as suggested by this one, but it's still not solving my problem.
As far as I know, the solution would be to reindex the database periodically. But reindexing would disable the search functionality and that's not an option in most of the cases.
Could anyone give some suggestions? Thanks.
I have a class which embedded some other classes by using #IndexedEmbedded annotation. Here is a simplified version of my class mapping.
Class A
#Entity(name = "classA")
#Indexed
public class classA extends Model {
private int id;
private String name;
private ClassB place;
...
some constructors
...
#Id
#GeneratedValue
#DocumentId
public int getId() {
return id;
}
#Column(name = "name")
#Field(analyze = Analyze.NO, store = Store.YES) // only used for sorting
public String getName() {
return name;
}
#IndexedEmbedded
#ManyToOne
#JoinColumn(name = "place_id")
public ClassB getPlace() {
return place;
}
...
}
Class B
#Entity(name = "classB")
public class classB extends Model {
private int id;
private String description;
...
some constructors
...
#Id
#GeneratedValue
public int getId() {
return id;
}
#Fields({
#Field,
#Field(name = "description_sort", analyze = Analyze.NO, store = Store.YES)
})
#ContainedIn
#Column(name = "description")
public String getDescription() {
return description;
}
...
}
And the indexing methods is as follows:
fullTextEntityManager.createIndexer()
.purgeAllOnStart(true)
.optimizeAfterPurge(true)
.optimizeOnFinish(true)
.batchSizeToLoadObjects(25)
.threadsToLoadObjects(8)
.startAndWait();
You placed ContainedIn annotation incorrectly. According the Hibernate Search documentation:
Be careful. Because the data is denormalized in the Lucene index when using the #IndexedEmbedded technique, Hibernate Search needs to be aware of any change in the Place object and any change in the Address object to keep the index up to date. To make sure the Place Lucene document is updated when it's Address changes, you need to mark the other side of the bidirectional relationship with #ContainedIn.
In your example, you need to:
Make the relationship between classes bidirectional
Mark the relationship in ClassB as ContainedIn
In your case:
ClassB {
private Set<ClassA> linkedObjects;
....
#OneToMany(mappedBy="place")
#ContainedIn
public Set<ClassA> getLinkedObjects() {
return linkedObjects;
}
....
}
I had a similar problem but already with correct annotations. In my case, I have added forced flush both to the database and to index and refreshed it afterward:
myEm.flush();
Search.getFullTextEntityManager(myEm).flushToIndexes();
myEm.refresh(updatedObject);
hmmm, add #ContainedIn doesn't work for me.
I put the sample project here
https://github.com/yhjhoo/princeSSH
Update department object is not able to update person index

hibernate inheritance : How to protect base class entry on child class deletion

I have some trouble with Hibernate 4 and inheritance:
I use a ChildData class which inherit from BaseData by a JOIN inheritance strategy. My mapping is done by annotation in classes.
Everything is working fine except that when I delete a ChildData instance (with session.delete() or with a Hql query) the BaseData entry is also deleted.
I understand that in most case this is the awaited behavior, but for my particular case, I would like to preserve the BaseData entry no matter what for history purpose.
In other words I want all actions on the child class to be cascaded to base class except deletion.
I have already tried #OnCascade on the child class, with no success.
Is it a way to achieve this by code or do I have to use a SQL Trigger ON DELETE ?
EDIT :
Base Class
#Entity
#Table(name = "dbBenchHistory", uniqueConstraints = #UniqueConstraint(columnNames = "Name"))
#Inheritance(strategy = InheritanceType.JOINED )
public class DbBenchHistory implements java.io.Serializable {
private int id;
private String name;
private String computer;
private String eap;
private Date lastConnexion;
private Set<DbPlugin> dbPlugins = new HashSet<DbPlugin>(0);
private Set<DbSequenceResult> dbSequenceResults = new HashSet<DbSequenceResult>(
0);
public DbBenchHistory() {
}
public DbBenchHistory(int id, String name) {
this.id = id;
this.name = name;
}
public DbBenchHistory(int id, String name, String computer, String eap,
Date lastConnexion, Set<DbPlugin> dbPlugins,
Set<DbSequenceResult> dbSequenceResults) {
this.id = id;
this.name = name;
this.computer = computer;
this.eap = eap;
this.lastConnexion = lastConnexion;
this.dbPlugins = dbPlugins;
this.dbSequenceResults = dbSequenceResults;
}
#Id
#Column(name = "Id", unique = true, nullable = false)
#GeneratedValue(strategy=GenerationType.IDENTITY)
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
//Getters/Setters
Child Class :
#Entity
#Table(name = "dbBench")
#OnDelete(action=OnDeleteAction.NO_ACTION)
public class DbBench extends DbBenchHistory {
private Set<DbProgram> dbPrograms = new HashSet<DbProgram>(0);
private Set<DbUser> dbUsers = new HashSet<DbUser>(0);
public DbBench() {
}
public DbBench(Set<DbProgram> dbPrograms,
Set<DbUser> dbUsers) {
this.dbPrograms = dbPrograms;
this.dbUsers = dbUsers;
}
//Getters/Setters
But I'm starting to think that I was wrong from the beginning and that inheritance was not the good way to handle this. If nothing shows up I will just go for BenchHistory - Bench being a simple one-to-one relationship
EDIT2 :
I edit while I can't answer my own question for insuficient reputation
I feel completly stupid now that I found the solution, that was so simple :
As I said, I was using hibernate managed methods : session.delete() or hql query. Hibernate was doing what he was supposed to do by deletintg the parent class, like it would have been in object inheritance.
So I just bypass hibernate by doing the deletion of the child class with one of the simplest SqlQuery on earth. And the base class entry remain untouched.
I understand that I somehow violate the object inheritance laws, but in my case it is really handy.
Thanks to everyone for your time, and believ me when I say I'm sorry.
I don't think Hibernate/JPA supports this. What you basically want is conversion from a subclass to a superclass, and not a cascading delete. When you have an object of the subclass, the members from the superclass are treated no different than the members of the subclass.
This can be solved through writing some logic for it though:
public void deleteKeepSuperclassObject(final ChildData childData) {
final BaseData baseDataToKeep = new BaseData();
//populate baseDataToKeep with data from the childData to remove
em.persist(baseDataToKeep);
em.remove(childData);
}

How to add a JPA relationship against legacy database

I'm coming from a C# entity framework background and looking at JPA in a Java project so I'm hoping that what I'm facing is just a conceptual problem.
I've got a legacy database that I can't alter the schema of and I need to write a DAL.
I've generated (simplified for the example) the following entities...
#Entity
#Table(name = "crag", catalog = "rad_dbo")
public class CragEntity {
private int id;
#Column(name = "id")
#Id
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
private int fkSubRegionId;
#Column(name = "fk_subRegionId")
#Basic
public int getFkSubRegionId() {
return fkSubRegionId;
}
public void setFkSubRegionId(int fkSubRegionId) {
this.fkSubRegionId = fkSubRegionId;
}
}
and
#Table(name = "subRegion", catalog = "rad_dbo")
#Entity
public class SubRegionEntity {
private int id;
#Column(name = "id")
#Id
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
I've tried adding a relationship to CragEntity so that I can access its subRegion
#ManyToOne
#JoinColumn(name="fk_SubRegionId",nullable=false)
private SubRegionEntity subRegion;
but when I try to run
select c from CragEntity c where c.subRegion.region = :area
I get an exception
java.lang.RuntimeException: org.hibernate.QueryException: could
not resolve property: subRegion of: uk.co.bmc.rad.dal.CragEntity
Hopefully this is possible and I'm being slow...
Many thanks in advance for any help!
In your query you are searching for the property "subRegion" though in your entity definition you have the name "fkSubRegionId", so you must change the var name or the query. ;)
EDIT: Sorry i misreaded the relation.
Can you access the property (without making an HQL query) with the relationship inside the code?
Unless, you want to pick only certain fields in your query I would recommend a query like:
from CragEntity c where c.subRegion.region='theRegion'
It turns out there were several issues - one conceptual, one with how IntelliJ had generated a relationship I was copying and one between the chair and keyboard...
IntelliJ had picked the region to subregion relationship with the owner at the "wrong" end - probably a schema issue rather than IntelliJ's fault. Once I realised that and figured out the fix I could copy that to CragEntity and SubRegionEntity
In CragEntity I added:
private SubRegionEntity subRegion;
#ManyToOne
#JoinColumn(name="fk_SubRegionId",nullable=false)
public SubRegionEntity getSubRegion() {
return subRegion;
}
public void setSubRegion(SubRegionEntity subRegion) {
this.subRegion = subRegion;
}
and then in SubRegionEntity I added:
private List<CragEntity> crags;
#OneToMany(mappedBy = "subRegion")
List<CragEntity> getCrags() {
return crags;
}
public void setCrags(List<CragEntity> crags) {
this.crags = crags;
}
Also, it seem that any entity class that is going to be one end of a relationship has to implement serializable (I guess the entities get serialized into the owner. So that needed adding onto SubRegionEntity and RegionEntity
The silliness on my part was of course that the query should have been c.subRegion.region.name otherwise I was comparing an object of type RegionEntity with a string... doh - very stupid mistake on my part.
I'm new to TDD but as always as soon as I wrote tests for what I thought should be happening with the existing code I was walked through my errors (and given google keywords by the exceptions and errors :-))

Categories

Resources