Search code examples
javajdogoogle-cloud-datastore

Lazily loaded embedded objects are not fetched completely GAE datastore


I am facing weird problem with Embedded entity inside my parent entity.

Following is the code

Below is my child entity.

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class IOU{
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
    private String iouId;

    private String groupId;
    private String fromUserId;
    private String toUserId;
    private double amount; 
}

It's embedded inside group.

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Group {


    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
    private String groupId;


    private String groupName;
    private String groupType;
    private String ownerId;

    @Persistent(defaultFetchGroup = "true")
    private List<IOU> iouList;
}

I am doing a bit dirty work while storing them, I don't know if that's the problem. I store them as follows.

group = mgr.makePersistent(group);

ArrayList<IOU> alIOU = this.generateIOUEntries(alTotalMembers, group);
group.setIouList(alIOU);
group = mgr.makePersistent(group);

Above is done, since I need autogenerated groupId inside my IOU.

Now the problem is when I try to fetch my group. List of iou contains only amount as property.

{
    "groupId" : "agdmZW0tZGV2cgsLEgVHcm91cBgEDA",
    "groupName" : "Test",
    "ownerId" : "agdmZW0tZGV2cgoLEgRVc2VyGAEM",
    "members" : [ {
      "userId" : "agdmZW0tZGV2cgoLEgRVc2VyGAIM",
    }, {
      "userId" : "agdmZW0tZGV2cgoLEgRVc2VyGAMM",
    }, {
      "userId" : "agdmZW0tZGV2cgoLEgRVc2VyGAEM",
    } ],
    "membersIdList" : [ "agdmZW0tZGV2cgoLEgRVc2VyGAIM", "agdmZW0tZGV2cgoLEgRVc2VyGAMM", "agdmZW0tZGV2cgoLEgRVc2VyGAEM" ],
    "iouList" : [ {
      "amount" : 0.0
    }, {
      "amount" : 0.0
    }, {
      "amount" : 0.0
    } ]
}

Weird thing is that, if I restart the server. All values are fetched properly. I am new to this JDO world, so I tried various combinations of annotation but nothing helped. I am guessing this might be related to some caching technique which is flushed to DB when I stop the server.
fromUserId and toUserId are not fetched until I restart the server. Correct output looks like this.

{
    "groupId" : "agdmZW0tZGV2cgsLEgVHcm91cBgEDA",
    "groupName" : "Test",
    "ownerId" : "agdmZW0tZGV2cgoLEgRVc2VyGAEM",
    "members" : [ {
      "userId" : "agdmZW0tZGV2cgoLEgRVc2VyGAIM",
    }, {
      "userId" : "agdmZW0tZGV2cgoLEgRVc2VyGAMM",
    }, {
      "userId" : "agdmZW0tZGV2cgoLEgRVc2VyGAEM",
    } ],
    "membersIdList" : [ "agdmZW0tZGV2cgoLEgRVc2VyGAIM", "agdmZW0tZGV2cgoLEgRVc2VyGAMM", "agdmZW0tZGV2cgoLEgRVc2VyGAEM" ],
    "iouList" : [  {
  "fromUserId" : "agdmZW0tZGV2cgoLEgRVc2VyGAIM",
  "toUserId" : "agdmZW0tZGV2cgoLEgRVc2VyGAMM",
  "amount" : 0.0
}, {
  "fromUserId" : "agdmZW0tZGV2cgoLEgRVc2VyGAIM",
  "toUserId" : "agdmZW0tZGV2cgoLEgRVc2VyGAEM",
  "amount" : 0.0
}, {
  "fromUserId" : "agdmZW0tZGV2cgoLEgRVc2VyGAMM",
  "toUserId" : "agdmZW0tZGV2cgoLEgRVc2VyGAEM",
  "amount" : 0.0
} ]
}

Code to retrieve is as simple as following. To lazily load iouList I touch it by calling getIouList() on it.

Group group = mgr.getObjectById(Group.class, id);
group.getIouList()

Solution

  • I found answer to the problem.

    Following question mentions about the same problem. One-to-Many relationship. Select objects from datastore

    For now, I touched each IOU entry in the iouList to get them loaded.

    Group group = mgr.getObjectById(Group.class, id);
    group.getIouList()
    
    for(IOU objIOU : group.getIouList()){
        objIOU.getFromUserId();
    }
    

    Above code loads each property of the IOU in list.

    I am guessing that only amount was getting shown previously, since it being a primitive had value of zero and other properties were null, and nulls were excluded in the serialization while creating JSON.

    I might try approach of using following annotation and update about same.

    @Persistent(mappedBy = "restaurant",defaultFetchGroup = "true")