i have model of class City like below:
@Entity
public class City {
@Id
Long id;
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
I have another model class Person given below:
@Entity
public class Person {
@Id
Long id;
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
Key<City> city;
}
After that I generate the endpoints for both the class using android studio and deploy it.
here is code for the generated endpoints:
PersonEndpoint
@Api(
name = "personApi",
version = "v1",
resource = "person",
namespace = @ApiNamespace(
ownerDomain = "backend.faceattendence.morpho.com",
ownerName = "backend.faceattendence.morpho.com",
packagePath = ""
)
)
public class PersonEndpoint {
private static final Logger logger = Logger.getLogger(PersonEndpoint.class.getName());
private static final int DEFAULT_LIST_LIMIT = 20;
static {
// Typically you would register this inside an OfyServive wrapper. See: https://code.google.com/p/objectify-appengine/wiki/BestPractices
ObjectifyService.register(Person.class);
}
/**
* Returns the {@link Person} with the corresponding ID.
*
* @param id the ID of the entity to be retrieved
* @return the entity with the corresponding ID
* @throws NotFoundException if there is no {@code Person} with the provided ID.
*/
@ApiMethod(
name = "get",
path = "person/{id}",
httpMethod = ApiMethod.HttpMethod.GET)
public Person get(@Named("id") Long id) throws NotFoundException {
logger.info("Getting Person with ID: " + id);
Person person = ofy().load().type(Person.class).id(id).now();
if (person == null) {
throw new NotFoundException("Could not find Person with ID: " + id);
}
return person;
}
/**
* Inserts a new {@code Person}.
*/
@ApiMethod(
name = "insert",
path = "person",
httpMethod = ApiMethod.HttpMethod.POST)
public Person insert(Person person) {
// Typically in a RESTful API a POST does not have a known ID (assuming the ID is used in the resource path).
// You should validate that person.id has not been set. If the ID type is not supported by the
// Objectify ID generator, e.g. long or String, then you should generate the unique ID yourself prior to saving.
//
// If your client provides the ID then you should probably use PUT instead.
ofy().save().entity(person).now();
logger.info("Created Person.");
return ofy().load().entity(person).now();
}
/**
* Updates an existing {@code Person}.
*
* @param id the ID of the entity to be updated
* @param person the desired state of the entity
* @return the updated version of the entity
* @throws NotFoundException if the {@code id} does not correspond to an existing
* {@code Person}
*/
@ApiMethod(
name = "update",
path = "person/{id}",
httpMethod = ApiMethod.HttpMethod.PUT)
public Person update(@Named("id") Long id, Person person) throws NotFoundException {
// TODO: You should validate your ID parameter against your resource's ID here.
checkExists(id);
ofy().save().entity(person).now();
logger.info("Updated Person: " + person);
return ofy().load().entity(person).now();
}
/**
* Deletes the specified {@code Person}.
*
* @param id the ID of the entity to delete
* @throws NotFoundException if the {@code id} does not correspond to an existing
* {@code Person}
*/
@ApiMethod(
name = "remove",
path = "person/{id}",
httpMethod = ApiMethod.HttpMethod.DELETE)
public void remove(@Named("id") Long id) throws NotFoundException {
checkExists(id);
ofy().delete().type(Person.class).id(id).now();
logger.info("Deleted Person with ID: " + id);
}
/**
* List all entities.
*
* @param cursor used for pagination to determine which page to return
* @param limit the maximum number of entries to return
* @return a response that encapsulates the result list and the next page token/cursor
*/
@ApiMethod(
name = "list",
path = "person",
httpMethod = ApiMethod.HttpMethod.GET)
public CollectionResponse<Person> list(@Nullable @Named("cursor") String cursor, @Nullable @Named("limit") Integer limit) {
limit = limit == null ? DEFAULT_LIST_LIMIT : limit;
Query<Person> query = ofy().load().type(Person.class).limit(limit);
if (cursor != null) {
query = query.startAt(Cursor.fromWebSafeString(cursor));
}
QueryResultIterator<Person> queryIterator = query.iterator();
List<Person> personList = new ArrayList<Person>(limit);
while (queryIterator.hasNext()) {
personList.add(queryIterator.next());
}
return CollectionResponse.<Person>builder().setItems(personList).setNextPageToken(queryIterator.getCursor().toWebSafeString()).build();
}
private void checkExists(Long id) throws NotFoundException {
try {
ofy().load().type(Person.class).id(id).safe();
} catch (com.googlecode.objectify.NotFoundException e) {
throw new NotFoundException("Could not find Person with ID: " + id);
}
}
}
CityEndpoint
@Api(
name = "cityApi",
version = "v1",
resource = "city",
namespace = @ApiNamespace(
ownerDomain = "backend.faceattendence.morpho.com",
ownerName = "backend.faceattendence.morpho.com",
packagePath = ""
)
)
public class CityEndpoint {
private static final Logger logger = Logger.getLogger(CityEndpoint.class.getName());
private static final int DEFAULT_LIST_LIMIT = 20;
static {
// Typically you would register this inside an OfyServive wrapper. See: https://code.google.com/p/objectify-appengine/wiki/BestPractices
ObjectifyService.register(City.class);
}
/**
* Returns the {@link City} with the corresponding ID.
*
* @param id the ID of the entity to be retrieved
* @return the entity with the corresponding ID
* @throws NotFoundException if there is no {@code City} with the provided ID.
*/
@ApiMethod(
name = "get",
path = "city/{id}",
httpMethod = ApiMethod.HttpMethod.GET)
public City get(@Named("id") Long id) throws NotFoundException {
logger.info("Getting City with ID: " + id);
City city = ofy().load().type(City.class).id(id).now();
if (city == null) {
throw new NotFoundException("Could not find City with ID: " + id);
}
return city;
}
/**
* Inserts a new {@code City}.
*/
@ApiMethod(
name = "insert",
path = "city",
httpMethod = ApiMethod.HttpMethod.POST)
public City insert(City city) {
// Typically in a RESTful API a POST does not have a known ID (assuming the ID is used in the resource path).
// You should validate that city.id has not been set. If the ID type is not supported by the
// Objectify ID generator, e.g. long or String, then you should generate the unique ID yourself prior to saving.
//
// If your client provides the ID then you should probably use PUT instead.
ofy().save().entity(city).now();
logger.info("Created City.");
return ofy().load().entity(city).now();
}
/**
* Updates an existing {@code City}.
*
* @param id the ID of the entity to be updated
* @param city the desired state of the entity
* @return the updated version of the entity
* @throws NotFoundException if the {@code id} does not correspond to an existing
* {@code City}
*/
@ApiMethod(
name = "update",
path = "city/{id}",
httpMethod = ApiMethod.HttpMethod.PUT)
public City update(@Named("id") Long id, City city) throws NotFoundException {
// TODO: You should validate your ID parameter against your resource's ID here.
checkExists(id);
ofy().save().entity(city).now();
logger.info("Updated City: " + city);
return ofy().load().entity(city).now();
}
/**
* Deletes the specified {@code City}.
*
* @param id the ID of the entity to delete
* @throws NotFoundException if the {@code id} does not correspond to an existing
* {@code City}
*/
@ApiMethod(
name = "remove",
path = "city/{id}",
httpMethod = ApiMethod.HttpMethod.DELETE)
public void remove(@Named("id") Long id) throws NotFoundException {
checkExists(id);
ofy().delete().type(City.class).id(id).now();
logger.info("Deleted City with ID: " + id);
}
/**
* List all entities.
*
* @param cursor used for pagination to determine which page to return
* @param limit the maximum number of entries to return
* @return a response that encapsulates the result list and the next page token/cursor
*/
@ApiMethod(
name = "list",
path = "city",
httpMethod = ApiMethod.HttpMethod.GET)
public CollectionResponse<City> list(@Nullable @Named("cursor") String cursor, @Nullable @Named("limit") Integer limit) {
limit = limit == null ? DEFAULT_LIST_LIMIT : limit;
Query<City> query = ofy().load().type(City.class).limit(limit);
if (cursor != null) {
query = query.startAt(Cursor.fromWebSafeString(cursor));
}
QueryResultIterator<City> queryIterator = query.iterator();
List<City> cityList = new ArrayList<City>(limit);
while (queryIterator.hasNext()) {
cityList.add(queryIterator.next());
}
return CollectionResponse.<City>builder().setItems(cityList).setNextPageToken(queryIterator.getCursor().toWebSafeString()).build();
}
private void checkExists(Long id) throws NotFoundException {
try {
ofy().load().type(City.class).id(id).safe();
} catch (com.googlecode.objectify.NotFoundException e) {
throw new NotFoundException("Could not find City with ID: " + id);
}
}
}
I want to make relationship between City and Person such that many person can belongs to a city. Questions:
Is this the correct modelling of the class for this kind of relationship? if not please tell me the correct model of one-to-one and one-to-many relationship
how to insert record in the datastore for this kind of relationship through java code(endpoints) and through API explorer?
Is there any need of using @Parent annotation or @Index annotation?
After building this relationship, if I delete a city then all the person belonging to that city must be deleted automatically. Is this modelling able to achieve that? please tell me the code for to do this also. if not then how can I achieve that using relationship?
I can't answer any questions about Google Endpoints, but the basic idea of modeling Person with a Key field pointing at City is probably correct - assuming there are lots and lots of people to a city. You'll want to @Index the key field so that you can query for people in a city. Be aware that this query will be eventually consistent, so if you are adding/removing lots of People in a City, you'll want to put a delay between when you stop adding People and when you execute the delete.
You could model this so that City is the @Parent of Person. This would eliminate the eventual consistency, but it would mean you can never move a Person to a new City. It would also mean that no City or Person in that city can change more than once per second due to the transaction throughput limit of a single entity group. Assuming you're actually talking about Persons and Cities, you probably don't want this. But it depends on your dataset.
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