sean christe
sean christe

Reputation: 909

Objectify many to one with Parent and RequestFactory

I have a situation - in my EquipmentType class I have a list of equipment checkouts

List<Key<EquipmentCheckout>> field

after reading the answer to this question: Objectify Relationships: One-to-Many, Can I do this efficiently? - it seems as the more efficient way to do this is to create a class called EquipmentCheckouts which would look something like the following:

class EquipmentCheckouts
  @Id 
  Long id

  @Parent 
  EquipmentType equipmentType

  @Indexed
  List<EquipmentCheckout> equipmentCheckouts

now - here's what I'm wondering - I'm using RequestFactory and I believe the RequestFactory has to have a find(Long id) method. From what I understand in order to retrieve an EquipmentCheckouts object with an EquipmentType parent you would have to do something along the lines of the following:

Key<EquipmentType> key = ObjectifyService.factory().getKey(equipmentType)
return ofy.get(new Key<EquipmentCheckouts>(key, EquipmentCheckouts.class, id))

So, if you couldn't have the EquipmentType in the find(Long id) method how are you supposed to do this?

For everything else in my system I have a Business parent which is stored in the logged in users session, that way when I go to retrieve everything I authenticate the user then key the business to find whatever it is. I feel as if there's something i'm not understanding about using @Parent in Objectify correctly.

Upvotes: 0

Views: 1014

Answers (3)

manubot
manubot

Reputation: 290

Ruslan answer is spot-on. It solves the issue for Entities with Parents and still work for root-entities.

I copy here an updated version of the locator code using Objectify 4 in case it is useful for anyone passing by.

  @Override
  public EntityObject find(Class<? extends EntityObject> clazz, String id) {

      Key<EntityObject> key = Key.create(id);

      EntityObject ob = ofy().load().key(key).now();
      return ob;
  }


  @Override
  public String getId(EntityObject domainObject) {

      if (domainObject.getId() != null)
      {
          Key<EntityObject> key = Key.create(domainObject);
          return key.getString();
      } else
          return null;
  }

Upvotes: 0

expert
expert

Reputation: 30095

You need to implement your own Locator that would support entities with parent. As you correctly noted you can't just use long ID because it doesn't have Key of a parent. I solved this issue by implementing Locator that uses composite string key that contains full path to the object.

The important thing here is that composite key is used only for RPC. Your entities still use long ID and don't have to be modified.

Here is code snippet:

public class PojoLocator extends Locator<DatastoreObject, String>
{
    @Override
    public DatastoreObject find(Class<? extends DatastoreObject> clazz, String id)
    {
        Key<DatastoreObject> key = Key.create(id);
        return ofy.load(key);
    }

    @Override
    public String getId(DatastoreObject domainObject)
    {
        if (domainObject.getId() != null)
        {
            Key<DatastoreObject> key = ofy.fact().getKey(domainObject);
            return key.getString();
        } else
            return null;
    }
}

You can see full version of my locator here.

Upvotes: 2

Peter Knego
Peter Knego

Reputation: 80330

It does not have to be only Long in RequestFactory interface. As docs say :

Built-in value types: BigDecimal, BigInteger, Boolean, Byte, Enum, Character, Date,      Double, Float, Integer, Long, Short, String, Void
Custom value types: any subclass of ValueProxy
Entity types: any subclass of EntityProxy
Collections: List<T> or Set<T>, where T is one of the above value or entity types

So you can have two longs: find(Long, Long). One for the parent and the er for the enntity.

Upvotes: 0

Related Questions