I'm new to RequestFactory but with generous help of Thomas Broyer and after reviewing documents below it's getting much better :)
But could you please explain why Locator<>.find()
is being called so unnecessarily (in my opinion) often ?
In my sample project I have two entities Organization and Person that maintain parent-child relationship. When I fetch Organization Objectify automatically fetches child Person.
Also I created two methods in my service layer findOrganizationById
and saveOrganization
that load and persist objects.
Now consider two scenarios:
When I call findOrganizationById
in the client following calls occur on server side:
OrderDao.findOrganizationById(1)
PojoLocator.getId(Key<?>(Organization(1)))
PojoLocator.getId(Key<?>(Organization(1)/Person(2)))
PojoLocator.getId(Key<?>(Organization(1)))
PojoLocator.find(Key<?>(Organization(1)))
PojoLocator.getId(Key<?>(Organization(1)/Person(2)))
PojoLocator.find(Key<?>(Organization(1)/Person(2)))
By calling OrderDao.findOrganizationById
I've already received full graph of objects. Why call .find
twice in addition to that? It's extra load on Datastore that cost me money. Of course I cache it but it would be neat to fix it. How can I avoid these additional calls ?
Similar thing happens when I save object(s) by calling saveOrganization
in the client. Following calls occur on server side:
PojoLocator.find(Key<?>(Organization(1)))
PojoLocator.find(Key<?>(Organization(1)/Person(2)))
OrderDao.saveOrganization(1)
PojoLocator.getId(Key<?>(Organization(1)))
PojoLocator.find(Key<?>(Organization(1)))
PojoLocator.getId(Key<?>(Organization(1)/Person(2)))
PojoLocator.find(Key<?>(Organization(1)/Person(2)))
I can understand need for fetching two objects from DataStore before updating it. RequestFactory sends deltas to the server so it needs to have entire object before persisting it. Still since I load full graph at once it would be nice not to have second call which is PojoLocator.find(Key<?>(Organization(1)/Person(2)))
. And I truly can't understand need for .find()
calls after persisting.
Thoughts ?
My proxies
@ProxyFor(value = Organization.class, locator = PojoLocator.class)
public interface OrganizationProxy extends EntityProxy
{
public String getName();
public void setName(String name);
public String getAddress();
public void setAddress(String address);
public PersonProxy getContactPerson();
public void setContactPerson(PersonProxy contactPerson);
public EntityProxyId<OrganizationProxy> stableId();
}
@ProxyFor(value = Person.class, locator = PojoLocator.class)
public interface PersonProxy extends EntityProxy
{
public String getName();
public void setName(String name);
public String getPhoneNumber();
public void setPhoneNumber(String phoneNumber);
public String getEmail();
public void setEmail(String email);
public OrganizationProxy getOrganization();
public void setOrganization(OrganizationProxy organization);
}
My service
public interface AdminRequestFactory extends RequestFactory
{
@Service(value = OrderDao.class, locator = InjectingServiceLocator.class)
public interface OrderRequestContext extends RequestContext
{
Request<Void> saveOrganization(OrganizationProxy organization);
Request<OrganizationProxy> findOrganizationById(long id);
}
OrderRequestContext contextOrder();
}
and finally my Locator<>
public class PojoLocator extends Locator<DatastoreObject, String>
{
@Inject Ofy ofy;
@Override
public DatastoreObject create(Class<? extends DatastoreObject> clazz)
{
try
{
return clazz.newInstance();
} catch (InstantiationException e)
{
throw new RuntimeException(e);
} catch (IllegalAccessException e)
{
throw new RuntimeException(e);
}
}
@Override
public DatastoreObject find(Class<? extends DatastoreObject> clazz, String id)
{
Key<DatastoreObject> key = Key.create(id);
DatastoreObject load = ofy.load(key);
return load;
}
@Override
public Class<DatastoreObject> getDomainType()
{
return null; // Never called
}
@Override
public String getId(DatastoreObject domainObject)
{
Key<DatastoreObject> key = ofy.fact().getKey(domainObject);
return key.getString();
}
@Override
public Class<String> getIdType()
{
return String.class;
}
@Override
public Object getVersion(DatastoreObject domainObject)
{
return domainObject.getVersion();
}
}
The pairs of
getId
andfind
at the end are the default implementation ofLocator#isLive
: it assumes an object is live (i.e. still exists in the data store) if finding it by its ID returns a non-null value.RF checks each
EntityProxy
it ever seen during the request/response for their liveness when constructing the response, to tell the client when an entity has been deleted (on the client side, it'd then fire anEntityProxyChange
event with aDELETE
write operation.You can of course override
isLive
in yourLocator
with a more optimized implementation if you can provide one.