Objectify Delete doesn't seem to be working - google-app-engine

I'm trying to delete an entity from my datastore using objectify but doesn't seem to be deleted even after shutting down the instance and restarting it. This is what the entity looks like in the datastore (both when it's on the production server & dev server):
This is the code i'm using to try and delete it:
#ApiMethod(name = "deleteDataVersion")
public Result deleteDataVersion(#Named("id") String id) {
// Where id is the id of the entity in the datastore.
if (id != null && !id.equals("")) {
ofy().delete().type(DataVersion.class).id(id).now();
return new Result(Result.STATUS_SUCCESS);
} else
return new Result(Result.STATUS_FAILED);
}
I've also tried this code:
#ApiMethod(name = "deleteDataVersion")
public Result deleteDataVersion(#Named("id") String id) {
if (id != null && !id.equals("")) {
// DataVersion doesn't have a parent.
Key<DataVersion> key = Key.create(null, DataVersion.class, id);
ofy().delete().key(key).now();
return new Result(Result.STATUS_SUCCESS);
} else
return new Result(Result.STATUS_FAILED);
}
But the entity never gets deleted. This is the code for my entity:
#Entity
public class DataVersion {
#Id
private Long id;
String folderName;
#Index
String effective;
public DataVersion() {
}
public DataVersion(String folderName, String effective ) {
this.folderName= folderName;
this.effective = effective;
}
// Getters & setters..
}
I just can't seem to find the problem :( Any help would be greatly appreciated! I'm sure it's something minor I'm overlooking (fairly new to Objectify/AppEngine).

The ID you have in parameter in your Endpoint is a String, and you try to delete the object DataVersion where the ID is a Long.
ofy().delete().type(DataVersion.class).id(Long.valueOf(id)).now();
would work better !

First get the key.
Key<DataVersion> key = Key.create(null, DataVersion.class, id);
Then fetch the entity from the database using the key.
DataVersion dataVersion = ofy().load().key(key).now();
Then delete the entity using objectify.
ofy().delete().entity(dataVersion).now();

Related

Objectify index is not created

I try to use objectify on google app engine standart environment and get exception. My classes look like this:
#Entity
public class Company {
#Id Long id;
#Index String companyName;
public Company() {
}
public Company(Long id, String companyName) {
this.id=id;
this.companyName = companyName;
}
}
#Entity
public class CompanyProject {
#Id Long id;
#Index String projectName;
#Parent Key<Company> owner;
public String cost;
public CompanyProject() {
}
public CompanyProject(long userId, String projectName) {
this();
this.projectName = projectName;
owner = Key.create(Company.class, userId); // Creating the Ancestor key
}
}
When I query data like this:
Key<Company> theUser = Key.create(Company.class, 1);
Iterable<CompanyProject> projects = ObjectifyService.ofy().load().type(CompanyProject.class).ancestor(theUser).order("projectName").list();
I get exception
com.google.cloud.datastore.DatastoreException: no matching index found. recommended index is:
- kind: CompanyProject
ancestor: yes
properties:
- name: projectName
Without order("projectName") query works just fine. Removed all entities of this kind from datastore, than added new, still get this exception. I use Gradle, not Maven if this matters. Maybe should be extra build step to create indexes or smth.
You are filtering on multiple properties (well, ancestor counts as 'another property') so you need a multi-property index defined in datastore-indexes.xml.
See the official documentation: https://cloud.google.com/appengine/docs/standard/java/config/indexconfig

SQLite Xamarin PCL

I am developing an App in Xamarin type PCL, for my DB structure, I want to use SQLite, but I have the following doubts ...
When entering a record in my DB, it takes the ID = 0, in my data model use
[PrimaryKey, AutoIncrement]
Public int ViolationID {get; set; }
And still, I enter the registry at zero, I do not know I'm doing wrong ... or is this a bug in the SQLite.NET-PCL package?
How can I verify that these records are actually being entered? I have in my code
public class DataAccess : IDisposable
{
private SQLiteConnection connection;
public DataAccess()
{
var entity = DependencyService.Get<IEntity>();
connection = new SQLiteConnection(entity.Plataforma, System.IO.Path.Combine(entity.DirectorioBD, "Infraccions.db3"));
connection.CreateTable<Infraccion>();
}
public void InsertInfraccion(Infraccion infraccion)
{
connection.Insert(infraccion);
}
public void UpdateInfraccion(Infraccion infraccion)
{
connection.Update(infraccion);
}
public Infraccion GetInfraccion(int InfraccionID)
{
return connection.Table<Infraccion>().FirstOrDefault(c => c.InfraccionID == InfraccionID);
}
public List<Infraccion> GetInfraccions()
{
return connection.Table<Infraccion>().OrderBy(c => c.MotivoID).ToList();
}
public void DeleteInfraccion(Infraccion infraccion)
{
connection.Delete(infraccion);
}
public void Dispose()
{
connection.Dispose();
}
}
Should I create a table called Infraccions.db3 on my phone?
Thank you for your comments...
Are you saying that all new records have an ID of 0 and overwrite the existing record in the database?
If so, then this is how SQLite works - for int columns 0 is a valid value, so when the ID is 0 it will overwrite the record, instead of incrementing the value.
The correct way to use int primary keys is to define your primary key as a nullable int, that way the value for a new record is null, which will be updated to the next available id:
[PrimaryKey, AutoIncrement]
public int? ViolationID {get; set; }
Essentially change int to int?.
1) When entering a record in my DB, it takes the ID = 0, in my data
model use
You are using primary key and auto increment in your model that's means you are not able to enter 0 manually in the primary field and it takes automatically next value in this field.
2) How can I verify that these records are actually being entered?
You can get DB file path when you create your database and you can able to open and see that data.
(System.IO.Path.Combine(entity.DirectorioBD, "Infraccions.db3") )
There are many browser plugins to access the sqllite database.

Objectify One-to-Many and Many-To-One in Google App Engine

I'm creating simple backend on Google App Engine using Objectify, that can store Users and thier Recipes.
Model look like this:
User has many Recipes, every Recipe has one author.
I want to be able to:
Get list of Recipes with authors in it
Get list of Users without fetching all recipes
Get one User with all his recipes
According to guide I have done this:
#Entity
public class User {
#Id
private Long id;
#Index
private String name;
List<Recipe> recipes = new ArrayList<>();
/* Other fields */
}
and Recipe :
#Entity
public class Recipe {
#Id
Long id;
String name;
#Index
#Load
Ref<User> author;
/* Other fields */
}
I save Recipe with author (User object) in it.
and 2. requirements work fine,
but when I try to get User with all recipes like this:
public User get(#Named("id") long id) throws NotFoundException {
User user = ofy().load().type(User.class).id(id).now();
if (user == null) {
throw new NotFoundException("Could not find User with ID: " + id);
} else {
List<Recipe> recipes = ofy().load().type(Recipe.class).filter("author", user).list();
account.recipes = recipes;
}
return account;
}
I get empty recipe list.
What am I doing wrong ?
Your author property in your Recipe is a Ref, which is essentially a Key, so you need to filter on that key, like this:
List<Recipe> recipes = ofy().load().type(Recipe.class).filter("author =", Key.create(user)).list();
Incidentally, instead of using .now(), checking for null, then throwing an exception, you could use .safe() which does the same thing for you.

AppEngine + Datastore + Objectify: Http Request returns inconsistent responses

I am implementing AppEngine server as a backend for my Android application. I use Datastore, I query it via Objectify service and I use Endpoints that I call via URL.
I have an entity User with properties like this:
#Id
Long id;
/**
* Name or nickname of the user
*/
public String name;
#Index
public String email;
#JsonIgnore
List<Key<User>> friends;
public User()
{
devices = new ArrayList<String>();
friendsWithKey = new ArrayList<Key<User>>();
}
public static User findRecordById(Long id)
{
return ofy().load().type(User.class).id(id).now();
}
#ApiMethod(name = "friends", httpMethod = "GET", path = "users/{userId}/friends")
public JSONObject getFriends(#Named("userId") String userId)
{
User user = User.findRecordById(Long.parseLong(userId));
JSONObject friendsObject = new JSONObject();
JSONArray jsonArray = new JSONArray();
JSONObject friend;
List<User> userList = new ArrayList<User>();
if (user.friendsWithKey != null)
{
for (Key<User> id : user.friendsWithKey)
{
friend = new JSONObject();
User user1 = User.findRecordById(id.getId());
userList.add(user1);
friend.put("name", user1.name);
friend.put("email", user1.email);
friend.put("id", user1.id);user1.lastTimeOnline.getTime());
jsonArray.add(friend);
}
friendsObject.put("friends", jsonArray);
}
return friendsObject;
}
It sometimes returns only a subset of friends. It is weird and I do not get where I could go wrong. If I get the User object from the DB, it already has a wrong List of Key values. But if I look into the database via console, I can see all of the users that ahve been added as friends.
I reaally need to fix this bug. Please, help.
It is very strange because it only happens once in a while and is non-deterministic in every way.

Nullpointerexception throws when inserting entity using Auto-generated Classendpoint insert method

I am confused to using auto-generated endpoint class. I want to use generated endpoint to insert new object into datastore. But, an exception is throwing.
fooEndpoint.insertFoo(foo); // throws null pointer exception
My entity class is similar with the given example at this source: https://developers.google.com/appengine/docs/java/datastore/jpa/overview.
Here is my entity:
#Entity
public class Foo {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Key ID;
Here is the stack trace:
java.lang.NullPointerException
at org.datanucleus.api.jpa.JPAEntityManager.find(JPAEntityManager.java:318)
at org.datanucleus.api.jpa.JPAEntityManager.find(JPAEntityManager.java:256)
at com.FooEndpoint.containsFoo(FooEndpoint.java:150)
at com.FooEndpoint.insertFoo(FooEndpoint.java:96)
On the other side, I can insert new object when I use the EntityManager persist method. Because, this does not check exist or not on the datastore.
I expect that, classEndpoint insert method should save the object and assing auto key to ID field.
Or I need to initialize the ID field.
Here is auto-generated endpoint class insertFoo method.
/**
* This inserts a new entity into App Engine datastore. If the entity already
* exists in the datastore, an exception is thrown.
* It uses HTTP POST method.
*
* #param foo the entity to be inserted.
* #return The inserted entity.
*/
public Foo insertFoo(Foo foo) {
EntityManager mgr = getEntityManager();
try {
if (containsFoo(foo)) {
throw new EntityExistsException("Object already exists");
}
mgr.persist(foo);
} finally {
mgr.close();
}
return foo;
}
Here is the containsFoo method
private boolean containsFoo(Foo foo) {
EntityManager mgr = getEntityManager();
boolean contains = true;
try {
Foo item = mgr.find(Foo.class, foo.getID()); // exception occurs here
if (item == null) {
contains = false;
}
} finally {
mgr.close();
}
return contains;
}
foo.getID() is null. Because, it is new object. I am expecting that, app engine creates a key for it. Or I need to explicitly create a key for it?
Other fields in Foo class are simple types such as String and booleans.
Thanks for your time.
I had exactly the same problem.
I will present the way I worked around it.
Original auto-generated Endpoints class relevant code:
private boolean containsFoo(Foo foo) {
EntityManager mgr = getEntityManager();
boolean contains = true;
try {
Foo item = mgr.find(Foo.class, foo.getID());
if (item == null) {
contains = false;
}
} finally {
mgr.close();
}
return contains;
}
Changed relevant code to include a null check for the entity object that is passed as an argument.
private boolean containsFoo(Foo foo) {
EntityManager mgr = getEntityManager();
boolean contains = true;
try {
// If no ID was set, the entity doesn't exist yet.
if(foo.getID() == null)
return false;
Foo item = mgr.find(Foo.class, foo.getID());
if (item == null) {
contains = false;
}
} finally {
mgr.close();
}
return contains;
}
This way it will work as supposed, although I'm confident that more experienced answers and explanations will appear.
I was having the same exact problem after using the Eclipse Plugin to autogenerate the cloud endpoints (by selecting "Google > Generate Cloud Endpoint Class").
Following your advice, I added:
if(foo.getID() == null) // replace foo with the name of your own object
return false;
The problem was solved.
How is that Google hasn't updated the autogenerated code yet as this must be a highly recurring issue?
Thanks for the solution.

Resources