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
and find
at the end are the default implementation of Locator#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 an EntityProxyChange
event with a DELETE
write operation.
You can of course override isLive
in your Locator
with a more optimized implementation if you can provide one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With