问题
I'm developing an app with backend and I decided to try using Google App Engine for my backend. Since I'm really new on Google App Engine, I'm little bit confused with the logic.
Basically, I have a couple of model classes to represent my object types. Lets say one of them is User and another is Item. Users have items and an item can belong more than one user. So User X can have 25 items including Item A, and User Y can have totally different 20 items and also the Item A.
Right now my User class looks like this:
@Entity
public class User {
@Id private Long id;
private String name;
private String emailAddress;
private String photoURL;
//All getters and setters...
}
And my Item class is approximately same. One of my questions is, where should I add some kind of list, like a list of Items into User. And which annotation should I use? What will that annotation provide me as a result (a reference, an id or a complete object)?
Another question related to this is, in my endpoint class, how can I get a list of Items that a specific User has (or list of Users that owns a specific Item)?
One last totally unrelated question, should I do anything to make id
auto increment or will it be automatic if I won't provide any id while inserting an item?
回答1:
You can search in the datastore for 2 things: keys and indexed properties.
class Thing {
@Id Long id;
@Index String property;
}
At some point you save some entities
Thing thing1 = new Thing();
thing1.property = "yes";
Thing thing2 = new Thing();
thing2.property = "no";
ofy().save().entities(thing1, thing2).now();
Now you can search for all entities based on their indexed properties. E.g. for all things with property == "yes"
.
List<Thing> things = ofy().load().type(Thing.class).filter("property", "yes").list();
Would return exactly thing1
.
The same works with Lists of properties. And it works with lists of references/keys to other properties.
class User {
@Id Long id;
@Index List<Key<Item>> items;
}
class Item {
@Id
Long id;
}
List<User> searchUsersWithItem(long itemId) {
Key<Item> itemKey = Key.create(Item.class, itemId);
return ofy().load().type(User.class).filter("items", itemKey).list();
}
List<User> searchUsersWithItem(Item item) {
return ofy().load().type(User.class).filter("items", item).list();
}
// just loads all the referenced items in the owner
List<Item> searchItemsWithOwner(User owner) {
return new ArrayList<Item>(ofy().load().<Item>values(owner.items).values());
}
filter
works with refs, keys and entitiy instances.
To be found things must be indexed https://cloud.google.com/datastore/docs/concepts/indexes / https://github.com/objectify/objectify/wiki/Queries
What's left for you to decide is how you model your relation. There are multiple ways. A user that owns a set of items which can be owned by set of users is actually a many-to-many relation. You could represent it like
class User { List<Key<Item>> items; }
class Item { }
or
class User { }
class Item { List<Key<User>> owners; }
or
class User { List<Key<Item>> items; }
class Item { List<Key<User>> owners; }
or even
class User { }
class Item { }
class Ownership { Key<Item> item; Key<User> user; }
Each approach has it's ups and downs with respect to data consistency and searchability / performance. In the initial example it's trivial to search for all items of a user since all you have to to is to load that one user and you have the list of items. The other direction requires the query approach.
So with respect to search performance you benefit from having the list of owners in the items as well as the list of items in the user because that way you don't need queries at all. The big downside becomes data consistency. If you fail to update both user and item at the same time you can have items that believe to be owned by a user where the user thinks different.
The last approach, using an explicit "Ownership" entity is essentially the traditional pivot / junction table https://en.wikipedia.org/wiki/Many-to-many_%28data_model%29 that is the result of transforming a many-many relation into 2 one-many relations. Using that would result in easy consistency, but the worst query performance.
Parent relations can sometimes be useful but only if there is an actual 1 to many relation where the parent needs to exist.
Also note how keys are not foreign keys like in traditional SQL databases as they can exist without an entity. So you'll have to take care of consistency regardless of what you do.
来源:https://stackoverflow.com/questions/33701147/using-android-google-app-engine-on-android-studio