Summary: This article demonstrates how to build a program which supports Parent-Child Relationships with the GigaSpaces Data-Grid. The program allows for returning Child objects through methods invoked by the Parent. The application also demonstrates how to return a parent object through the child

Overview

The program below demonstrates how to build and implement Parent-Child relationships. In this example, the Parent object stores a reference to the Child object or objects within its class, rather than the Child object itself.

See the Modeling your Data section for details for when to construct strong parent-child relationships, i.e. embed the child object in the parent object, and when to create non-embedded relationships, where the child ID is included in the parent object.

When the Parent object stores a reference to the Child object, you may want to fetch the parent object that is associated with a child object. The example below demonstrates how ID operations handle relationships between objects. This example uses the ReadByIds batch operation to retrieve multiple space objects using on their ID:

IReadByIdsResult<Child> childrenObjResult = space.ReadByIds(Child.class,childrenIDs);

The application first writes 10000 parent-child graphs into the space. The write function creates two types of graphs:

  • Five graphs with the following values for the child objects: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
  • 9955 graphs with the following values for the child objects: 0, 10, 20, 30, 40, 50, 60, 70, 80, 90.


The example demonstrates a simple approach locating all the parent objects that have two child objects with values of 1 and 2 – effectively a join operation using ID operations. This will return 5 matching graphs.

Child class

Child
package com.j_spaces.examples.parentchild;

import com.gigaspaces.annotation.pojo.SpaceClass;
import com.gigaspaces.annotation.pojo.SpaceId;
import com.gigaspaces.annotation.pojo.SpaceIndex;
import com.gigaspaces.annotation.pojo.SpaceRouting;
import com.gigaspaces.metadata.index.SpaceIndexType;

//This is the child class object. Its ID will be stored in the Parent object. The Child class stores its parent id to create a dual 
//connection between the two classes. 

[SpaceClass]
public class Child {
	
	private string _parentID;
        private long _data;
        private string _id;

        public Child() { }

        public Child(String id, String parentID)
        {
            this._parentID = parentID;
            this._id = id;
        }

        public string ToString()
        {
            return "ID:" + _id + " data:" + _data;
        }
        
        [SpaceProperty(NullValue = 0)]
        [SpaceIndex(type = SpaceIndexType.BASIC)]
        public long data
        {
            get { return _data; }
            set { _data = value; }
        }


        [SpaceId(autoGenerate = false)]
        public string id
        {
	        get { return _id; }
                set { _id = value; }
	}

        [SpaceIndex(type = SpaceIndexType.BASIC)]
        [SpaceRouting]
        public string parentID
        {
	    get { return this._parentID; }
            set { this._parentID = value; }
	}

}

Parent class

Parent
package com.j_spaces.examples.parentchild;

import java.rmi.RemoteException;

import org.openspaces.core.GigaSpace;

import net.jini.core.entry.UnusableEntryException;
import net.jini.core.transaction.TransactionException;

import com.gigaspaces.annotation.pojo.SpaceClass;
import com.gigaspaces.annotation.pojo.SpaceId;
import com.gigaspaces.annotation.pojo.SpaceIndex;
import com.gigaspaces.annotation.pojo.SpaceRouting;
import com.gigaspaces.client.ReadByIdsResult;
import com.gigaspaces.metadata.index.SpaceIndexType;

//The parent class, which holds a string array, each entry referring to a different child ID. The Class also holds a copy of the //Child object, however this is for temporary use only and the Child object stored in the _children_ field is not stored in the //actual memory.
[SpaceClass]
public class Parent  {

	private string [] _childrenIDs;
    	private Child [] _children;
	private long _data;
	private string _id;
	
	static string ChildClassName = Child.class.getName();

	public Parent() 
        {
        }

	public Parent(string id) 
        {
		this._id = id;
	}

	public string GetChildrenDetails(ISpaceProxy space) 
	{
		String ret="";
		Child[] childs = GetChildren(space);
		for (int i=0;i<childs.Length ; i++)
		{
			ret = ret + childs[i].ToString() + " | ";
		}
		return ret;
		
	}

	public Child[] GetChildren(ISpaceProxy space) 
	{
		if (_children == null)
		{
			IReadByIdsResult<Child> childrenObjResult = space.ReadByIds(Child, _childrenIDs);
			_children = childrenObjResult.ResultsArray;
		}
		return _children;
	}
	
	public String GetChildrenIDs()
	{
		String res ="";
		for (int i=0 ; i< _childrenIDs.Length; i++)
		{
			res =res + _childrenIDs[i] + "\n";
		}
		return res;
	}

	[SpaceIndex(type=SpaceIndexType.BASIC)]
	public long Data 
        {
		get { return _data; }
                set { _data = value; }
	}

	public string[] ChildrenIDs 
        {
		get { return _childrenIDs; }
                set { _childrenIDs = value; }
	}

	[SpaceId(autoGenerate=false)]
	[SpaceRouting]
	public string Id
        {
		get { return _id; }
                set { _id = value; }
	}

    }

}

Application

Application
package com.j_spaces.examples.parentchild;

import java.rmi.RemoteException;
import java.util.HashSet;
import java.util.Set;

import org.openspaces.core.GigaSpace;
import org.openspaces.core.GigaSpaceConfigurer;
import org.openspaces.core.space.UrlSpaceConfigurer;
import net.jini.core.entry.UnusableEntryException;
import net.jini.core.transaction.TransactionException;
import com.gigaspaces.client.ReadByIdsResult;

public class ParentChildMain {

            static ISpaceProxy Space;
	    static int Max_graphs = 10000;
	    static int Matching_graphs = 5;

	    public static void main(String[] args) 
            {
		try 
                {
                        //Initalize the space object
			Space = GigaSpacesFactory.FindSpace("/./mySpace");

			Console.WriteLine("Write " + Max_graphs+ " parent/child graphs.\nWe will have 2 types of graphs:" +
					"\n" +  Matching_graphs+
						" graphs that got the following values for the child objects:0,1,2,3,4,5,6,7,8,9" +
					"\nand another "  +(Max_graphs - Matching_graphs) + 
						" graphs with the following values for the child objects:0,10,20,30,40,50,60,70,80,90");
			
			go();
			
		  } catch (Exception e) 
                  {
			    Console.WriteLine(e.Message);
             	  }		
             }
   
             static public void go() 
             {
			for (int i = 0; i < Max_graphs; i++) 
                        {
                             //Create the parent objects
		             Parent parent = new Parent(i +"");
                             //Create array of Child objects to be associated with the Parent object
			     Child [] children = new Child[10];
			     string [] childrenIDs = new String[10];
				
                             for (int j = 0; j < 10; j++) 
                             {
                                        //assign data to the child object
					children[j] = new Child(i + "_" + j, parent.Id);
					if (i% (Max_graphs/Matching_graphs) ==0)
						children[j].data = j;
					else
						children[j].data = j * 10;
						
					childrenIDs[j] = children[j].id;
			     }
                        //save the child ID values in the parent object
	                parent.ChildrenIDs = childrenIDs;
			//Save the parent object to the Space	
			Space.Write(parent);
                        //Save the Child array object to the Space
			Space.WriteMultiple(children);
			}

			FindMatchingGraph(1,2);
			FindMatchingGraph(3,4);
			FindMatchingGraph(5,6);
			FindMatchingGraph(7,8);
	}

	static void FindMatchingGraph(long value1, long value2) 
	{
		Console.WriteLine("-----------------------------------------------------------------");
		Console.WriteLine("Find all the parent objects that have 2 child objects with values: " + 
			value1 +" and " + value2+ "");
		Console.WriteLine("Both child objects have the same parent object");
		DateTime startTime = System.DateTime.Now;
		Object [] childrenResults1 = FindChildrenByValue(new long(value1));
		Set<String> parentIDs1 = GetParentIDsSet(childrenResults1);

		Object [] childrenResults2 = FindChildrenByValue(new Long(value2));
		Set<String> parentIDs2 = GetParentIDsSet(childrenResults2);
		
		Set<String> resultSet = AND(parentIDs1, parentIDs2);

		Parent [] parents = GetParentsfromIDs(resultSet);
		DateTime endTime = System.DateTime.Now;
        
		Console.WriteLine(" --->> Found " + parents.Length +
			" matching Parent objects in " + (double)(((double)endTime - (double)startTime)/1000) + " micro second");
		
		for (int i = 0; i < parents.Length; i++) {
			Console.WriteLine("Found Parent Object:" + parents[i]
					+ " - ID:" + parents[i].Id + " - Children objects:\n\t"
					+ parents[i].GetChildrenDetails(Space));
		}
		
	}
		
	static public Object[] FindChildrenByValue(long value) {
		Child childTemplate = new Child();
		childTemplate.data = value;
		return Space.ReadMultiple(childTemplate , int.MaxValue);
	}
	
	static public Set<String> GetParentIDsSet(Object [] entries) {
		HashSet<String> result = new HashSet<String>();
		for (int i = 0; i < entries.Length; i++) {
			result.Add(((Child) entries[i]).parentID));
		}
		return result;
	}
	
	static public Parent[] GetParentsfromIDs(Set ids) 
	{
		IReadByIdsResult<Parent> parentObjResult = Space.ReadByIds(Parent.class, ids.toArray());
		return parentObjResult.getResultsArray();
	}
	
	// find union between set1 and set2
	static public Set<String> AND(Set<String> set1, Set<String> set2) {
		HashSet<String> result = new HashSet<String>(set1);
		result.retainAll(set2);
		return result;
	}
    }
}

Expected output

Write 10000 parent/child graphs.
We will have 2 types of graphs:
5 graphs that got the following values for the child objects:0,1,2,3,4,5,6,7,8,9
and another 9995 graphs with the following values for the child objects:0,10,20,30,40,50,60,70,80,90
-----------------------------------------------------------------
Find all the parent objects that got 2 child objects with values 1 and 2
Both child objects have the same parent object
 --->> Found 5 matching Parent objects in 623.38 micro second
Found Parent Object:com.j_spaces.examples.parentchild.Parent@335053 - ID:8000 - Children objects:
	ID:8000_0 data:0 | ID:8000_1 data:1 | ID:8000_2 data:2 | .... 
Found Parent Object:com.j_spaces.examples.parentchild.Parent@1c0cd80 - ID:0 - Children objects:
	ID:0_0 data:0 | ID:0_1 data:1 | ID:0_2 data:2 | ... 
Found Parent Object:com.j_spaces.examples.parentchild.Parent@f3c5c4 - ID:6000 - Children objects:
	ID:6000_0 data:0 | ID:6000_1 data:1 | ID:6000_2 data:2 | ...
Found Parent Object:com.j_spaces.examples.parentchild.Parent@3ce725 - ID:4000 - Children objects:
	ID:4000_0 data:0 | ID:4000_1 data:1 | ID:4000_2 data:2 | ...  
Found Parent Object:com.j_spaces.examples.parentchild.Parent@6b6ac8 - ID:2000 - Children objects:
	ID:2000_0 data:0 | ID:2000_1 data:1 | ID:2000_2 data:2 | ...
GigaSpaces.com - Legal Notice - 3rd Party Licenses - Site Map - API Docs - Forum - Downloads - Blog - White Papers - Contact Tech Writing - Gen. by Atlassian Confluence