Jan 27, 2009

Hibernate Composite Keys Bug

Hi,

While working on the last few weeks on the last Gigaspaces XAP version, we were upset to find that it does not support composite keys (2 or more fields that serve as the table primary key) when using the default Hibernate connector.

When we investigated the issue, we found out that since Gigaspaces XAP is heavily relayed on Hibernate, and since Hibernate does not support this, Gigaspaces does not support this as well. UPDATE: Gigaspaces is not heavily relayed on Hibernate, rather than provides Hibernate as its default out of the box ORM mapping solution.

It seems that we are not the only one who suffers from this issue in Hibernate (see the error code: Expected positional parameter count: 1, actual parameters: [Parent@bec357b] [from Child this where this.id.parent = ?])

We are working on an applicative solution to solve this issue, but not found time yet to get deep into the Hibernate source code and solve this issue due time stress.

Hope somebody will solve that, before we'll get to it again :-)

UPDATE: Please notice the thread regarding this post which discuss Gigaspaces other external data sources, virtual fields, how to overcome this Hibernate composite keys limitation and their drawbacks.

Best Regards,
Moshe. RockeTier. The Performance Experts.

4 comments:

Shay Hassidim said...

GigaSpaces is not heavily depended on Hibernate. You can implement External Data source to any database using any other ORM available.
You can create a "virtual field" as part of the Space Class POJO that will be indexed and will be based on multiple real field’s data.
You simply need to have a getter for this field to return the composite data when the object is indexed.
This will allow you to fetch data.
If you use the space to fetch your data - you don’t have to map this composite field to a relevant database table.
See simple example code below.
package com.test;


import org.openspaces.core.GigaSpace;
import org.openspaces.core.GigaSpaceConfigurer;
import org.openspaces.core.space.UrlSpaceConfigurer;

import com.gigaspaces.annotation.pojo.SpaceClass;
import com.gigaspaces.annotation.pojo.SpaceId;
import com.gigaspaces.annotation.pojo.SpaceProperty;
import com.gigaspaces.annotation.pojo.SpaceProperty.IndexType;
import com.j_spaces.core.client.EntrySnapshot;
import com.j_spaces.core.client.ExternalEntry;

@SpaceClass
public class CompositeExample {
public CompositeExample (){}

public static void main(String[] args) throws Exception{
GigaSpace space = new GigaSpaceConfigurer(new UrlSpaceConfigurer("jini://*/*/mySpace")).gigaSpace() ;
CompositeExample obj = new CompositeExample ();
obj.setF1("A");
obj.setF2("B");
space.write(obj);

String STR = String.class.getName() ;
ExternalEntry templ= new ExternalEntry (CompositeExample.class.getName() , new Object[4] , new String[]{"composite","f1","f2" ,"id"} , new String[]{STR,STR,STR,STR});
templ.setFieldValue(templ.getFieldPosition("composite") , "A B");
ExternalEntry rets[] = space.readMultiple(templ,Integer.MAX_VALUE);
System.out.println("found " + rets.length + " matching objects");
for (int i = 0; i < rets.length; i++) {
ExternalEntry entry = rets[i];
System.out.println(entry.getObject(space.getSpace()));
}
}

private String f1 = null;
private String f2= null;
private String comp= null;
private String id = null;

@SpaceProperty(index=IndexType.BASIC)
public String getComposite() {
return f1 + " " + f2;
}

public void setComposite(String comp) {
this.comp = comp;
}

public String getF1() {
return f1;
}
public void setF1(String f1) {
this.f1 = f1;
}
public String getF2() {
return f2;
}
public void setF2(String f2) {
this.f2 = f2;
}
public String toString()
{
return "ID="+ getId() + " F1="+getF1() + " F2=" + getF2() + " Composite=" +getComposite();
}

@SpaceId (autoGenerate=true)
public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}
}

gnirpaz said...

Moshe,
Hibernate may not support composite keys, however it is incorrect to say that GigaSpaces XAP heavily relies on Hibernate.
GigaSpaces XAP uses Hibernate as one of the external data source integration implementations, however this implementation is not the only one and it can be easily replaced by other implementations at your choice.

I advised you to write your own external data source implementation using JDBC , JPA, or iBatis.

Guy Nirpaz,
GigaSpaces

Moshe Kaplan said...

Dear Shay and Guy,

You are absolutely right that Gigaspaces supports other ORM external databases, and that composite key issue can be solved in other ways.

However, Hibernate is the only external data source that is provided as a built in/out of the box component in the Gigaspaces framework.

Shay, thank you for contributing this code example that presents how to implement a virtual field in Gigaspaces. However, this code example does not present how to map this virtual fields to the database.

This virtual field solution has major drawbacks since it requires in the LRU/Read Through case, implementation of a new composed field in the database. In cases where the target table has hundreds of millions of rows and only 3 fields, 4 byte each: 2 key fields and third is the data (for example impressions counter), the result of adding a new composite keys of size of 8 bytes, will be expanding the whole database size in over 50%. Another case that this solution is not acceptable is when you boostexisting software and cannot change existing database scheme

Probably the solution is writing a DAL layer, which requires a significant amount of work and is not so out of the box...

As always, I believe we'll manage to meet the client deadlines and helping them boost their system

Best Regards,
Moshe. RockeTier. The Performance Experts

Moshe Kaplan said...

Hi Shay and Guy,

Please notice as well the following that the following links are semi broken: How to implement a custom data source: http://www.gigaspaces.com/wiki/display/XAP66/Custom+Data+Source
External Data Source Operations
http://www.gigaspaces.com/wiki/display/XAP66/External+Data+Source+Operations

I also believe that since you provide Hibernate as an out of the box feature, you should comments regarding that: "GigaSpaces External Data Source provides the DataProvider/DataPersister interfaces (with a built in implementation using Hibernate) which can be used to store data in an existing data source and in the space. Data is loaded from the data source during space initialization (DataProvider), and from then onwards the application works with the space directly. Meanwhile, the data source is constantly updated with all the changes made in the space (DataPersister)." from: http://www.gigaspaces.com/wiki/display/XAP66/External+Data+Source

Best
Moshe. RockeTier. The Performance Experts.

ShareThis

Intense Debate Comments

Ratings and Recommendations