I am new to Greendao.I am writing a generator for generating entities in greendao.So,I have two entities Hospital and patient. They have a one to many relationship between them. So,a hospital can have many patients but one patient can have only one hospital. Now Property hospitalId = patient.addLongProperty("hospitalId").getProperty(); this adds a hospitalid column to patient table. and
ToMany hospitalToPatients = hospital.addToMany(patient, hospitalId);
This line creates a one to many relationship between hospital and patient.So what is the use of the lines patient.addToOne(hospital, hospitalId); and hospitalToPatients.setName("patients"); How to implement one to one,one to many,many to one and many to many relationships in greendao ?
PS: I copied this code from http://www.vertabelo.com/blog/technical-articles/a-comparison-of-android-orms
public class ProjectGenerator {
public static void main(String[] args) throws Exception {
Schema schema = new Schema(1, "com.example.project");
// hospital table
Entity hospital = schema.addEntity("Hospital");
hospital.addIdProperty();
hospital.addStringProperty("name");
// patient table
Entity patient = schema.addEntity("Patient");
patient.addIdProperty();
patient.addStringProperty("name");
Property hospitalId = patient.addLongProperty("hospitalId").getProperty();
// patient has a one assigned hospital
patient.addToOne(hospital, hospitalId);
// hospital has many patients
ToMany hospitalToPatients = hospital.addToMany(patient, hospitalId);
hospitalToPatients.setName("patients");
// trigger generation with path to the Android project
new DaoGenerator().generateAll(schema, "../project/src/main/java");
}
}
So what is the use of the lines patient.addToOne(hospital, hospitalId)
This line is creating a oneToOne relation between hospital and patient .
hospitalToPatients.setName("patients")
This is just setting the name of foreign key .
As you can see, you have already implemented implement one to one,one to many relationship in your example . patient.addToOne is an example of OneToOne relationships . hospital.addToMany is an example of OneToMany relationships . And greenDao doesn't support ManyToMany relationship directly for more details you can read this .
Related
I have three parse subclasses: Recipe, Ingredient, and RecipeIngredient. RecipeIngredient has a pointer to a Recipe, and a pointer to an Ingredient.
When I am trying to create a QueryFactory to get all the ingredients for a recipe. I am trying to do this with whereMatchesKeyInQuery, but the objectIds aren't matching. From the docs, it appears that this should be legal. What am I missing?
public MeatIngredientListAdapter(Context context, final String recipeName) {
super(context, new ParseQueryAdapter.QueryFactory<Ingredient>() {
public ParseQuery<Ingredient> create() {
ParseQuery<Ingredient> query = ParseQuery.getQuery(Ingredient.class);
query.whereEqualTo("isMeatOrFat", true);
ParseQuery<RecipeIngredient> riQuery = ParseQuery.getQuery(RecipeIngredient.class);
riQuery.whereEqualTo("recipeName", recipeName);
riQuery.include("ingredient");
riQuery.whereEqualTo("isMeatOrFat", true);
query.whereMatchesKeyInQuery("objectId", "ingredient.objectId", riQuery);
return query;
}
});
}
In your case the use of whereMatchesKeyInQuery is overkill. I might not have enough information to make this call about your app but is seems that you would be able to cut out the need for RecipeIngredient all together if you just create a Relation of the Ingredient class inside the Recipe class. This will simplify your queries and make your app more scalable and give you features (explained below). If you had a data structure like this:
Recipe Class
- Name (String)
- ingredients (Relation of the Ingredient class)
Ingredient Class
- <Columns to describe the ingredient that you already have in place>
Now you can store one recipe that "points" (using relations) to many ingredients.
So an example entry might look like this:
Recipe
Name
PB&J
ingredients
Peanut Butter //this is a relation to the Peanut Butter Ingredient object
Jelly //this is a relation to the Jelly Ingredient object
Ingredient
Name
Peanut Butter
Calories
...
Cost
...
And here in code we add the data to the classes:
ParseObject ingredient1 = new ParseObject(Ingredient.class);
ingredient1.put("Name", "Peanut Butter");
ParseObject ingredient2 = new ParseObject(Ingredient.class);
ingredient1.put("Name", "Jelly");
ParseObject recipe = new ParseObject("Recipe");
recipe.put("Name", "PB&J");
ParseRelation<ParseObject> relation = recipe.getRelation("ingredients");
relation.add(ingredient1);
relation.add(ingredient2);
recipe.saveInBackground();
The magic behind this setup is that we can now specify a recipe by name and get all ingredients like you wanted but we can also retrieve all recipes that have certain ingredient(s) in them (this is the beauty of a many-to-many relationship) and on top of that it simplifies your queries.
Now for the original query you wanted with this new setup:
ParseObject recipe = ...; // "PB&J" Recipe object.
ParseRelation relation = recipe.getRelation("ingredients");
// generate a query based on that relation
ParseQuery query = relation.getQuery();
query will hold all of the ingredients for the recipe object when the query is executed.
Now suppose you want to create a query where you get all of the recipes that contain a certain ingredient:
ParseObject ingredient = ...
ParseQuery<ParseObject> query = ParseQuery.getQuery("Recipe");
query.whereEqualTo("ingredients", ingredient); //use whereContainedIn for multiple ingredients
query will contain all Recipe objects that have the specified ingredient in their ingredients relation column when the query is executed.
I hope this helped you. Please let me know if I severely misunderstood the structure of your app - if so I will revise my answer if you give me new information but honestly I think the "middle man" RecipeIngredient is forcing you to complicate your app.
I am trying to figure out how to model this relation for Android in GreenDao.
We have a NavigationNode, which can have ManytoMany other NavigationNodes.
In Rails we modelled this with a 'has_many :through' with a NavigationPath join table:
class NavigationPoint < ActiveRecord::Base
has_many :navigation_paths, dependent: :destroy
has_many :paths, through: :navigation_paths, source: :navigation_point, dependent: :destroy
end
class NavigationPath < ActiveRecord::Base
attr_accessible :navigation_point_id, :connected_point_id
belongs_to :navigation_point, foreign_key: :connected_point_id
end
And in iOS we just set it as a relation to self on NavigationNode:
Relationship Destination Inverse
-------------------------------------------
paths NavigationNode paths
But I can't seem to find the right configuration for greenDAO.
Any help / hint would be appreciated, thanks
Update:
I implemented a temporary solution for now:
The DAO for NavigationPath (the join table):
Entity navigationPath = schema.addEntity("NavigationPath");
navigationPath.setSuperclass(SUPER_CLASS);
navigationPath.setIsJoinTable(true);
navigationPath.addIdProperty();
Property fromNavigationNodeProperty = navigationPath.addLongProperty("NavigationNodeID").getProperty();
Property toNavigationNodeProperty = navigationPath.addLongProperty("toNavigationNodeID").getProperty();
ToMany paths = navigationNode.addToMany(navigationPath, fromNavigationNodeProperty, "navigationPaths");
Index indexNavigationPath = new Index();
indexNavigationPath.addProperty(fromNavigationNodeProperty);
indexNavigationPath.addProperty(toNavigationNodeProperty);
indexNavigationPath.makeUnique();
navigationPath.addIndex(indexNavigationPath);
And here the custom relation method in NavigationPath:
public List<NavigationNode> getPaths(String where) {
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
NavigationPathDao pathDao = daoSession.getNavigationPathDao();
QueryBuilder pathsQuery = pathDao.queryBuilder().where(NavigationPathDao.Properties.NavigationNodeID.eq(id));
List<NavigationPath> navigationPaths = pathsQuery.list();
List<NavigationNode> navigationNodesNew = new ArrayList<NavigationNode>();
for (NavigationPath path : navigationPaths) {
Long id = path.getToNavigationNodeID();
NavigationNode node = myDao.load(id);
if (node != null)
navigationNodesNew.add(node);
}
return navigationNodesNew;
}
It's a pretty naive implementation, but for now it is working.
But again, tips are appreciate.
From greenDao website:
Many-to-Many Relations (n:m)
In databases, n:m relations are modeled using a join table. The join
table holds entries having rows with foreign keys to each of the
relating tables. While greenDAO does not support n:m relations
directly as of now, you can model the join table as a separate entity.
In practice, you often have “relation entities” with additional
properties, so you might want to do so anyway. In future releases,
greenDAO might introduce direct support of n:m relations.
It seems that isn't possible at this moment without a relation entity, maybe you could try that.
If i have for example a table Shows and i have a to-many relation to a table Actors
When inserting a Show which doesn't have id(its auto-generated), how can i insert Actors if i don't have id of the show to relate to?
Here is DaoGenerator code:
Entity show = schema.addEntity("Show");
show.setHasKeepSections(true);
show.addIdProperty();
show.addIntProperty("tvdb_id").notNull();
show.addStringProperty("title");
show.addIntProperty("year");
show.addStringProperty("url");
show.addLongProperty("first_aired");
show.addStringProperty("country");
show.addStringProperty("overview");
show.addIntProperty("runtime");
show.addStringProperty("status");
show.addStringProperty("network");
show.addStringProperty("air_day");
show.addStringProperty("air_time");
show.addStringProperty("certification");
show.addStringProperty("imdb_id");
show.addIntProperty("tvrage_id");
show.addLongProperty("last_updated");
show.addIntProperty("rating");
show.addIntProperty("votes");
show.addIntProperty("loved");
show.addIntProperty("hated");
Entity actor = schema.addEntity("Actor");
actor.addIdProperty();
actor.addStringProperty("name");
actor.addStringProperty("character");
actor.addStringProperty("image");
Property showId = actor.addLongProperty("show_id").notNull().getProperty();
ToMany showToActor= show.addToMany(actor, showId);
showToActor.setName("actors");
The ID is auto-generated when you insert the object.
So you have to insert the show before adding actors to it.
You can just call refresh() on that entity, the current copy would get updated and so its id.
Then you should take this showId and set it to each actor's show id.
show.refresh();
for (Actor actor : actors)
actor.setShowId(show.getId());
actorDao.insertAllInTx(actors);
I'm using greenDao and I need to extract data from several tables similar to left-join funcionality. Here's a cite from my schema generator:
private static void genRetailers(Schema schema) {
// create retailer entity
Entity retailerEntity = schema.addEntity("Retailer");
retailerEntity.addIdProperty().notNull();
retailerEntity.addStringProperty("title");
Entity shopEntity = schema.addEntity("Shop");
shopEntity.addIdProperty().notNull();
shopEntity.addStringProperty("address");
Property retailerId = shopEntity.addLongProperty("retailerId")
.getProperty();
// (1) Retailer < - > (*) Shop
retailerEntity.addToMany(shopEntity, retailerId);
}
When I do:
return (ArrayList<Retailer>) mDaoSession.getRetailerDao()
.queryBuilder().list();
I only get contents of the Retailer table itself, however I also need Shop entity values which're null. Only after I call getShops() the entities get filled. I need to fill entities right at the first query. How is it done ?
Thanks.
Use the queryDeep method:
return mDaoSession.getRetailerDao().queryDeep(null);
I need to use classes to represent entities in database, here are some information:
=== TABLEs ===
SHOP
shop_id(primary)
name
owner
FAVOURITES LIST
fav_id(primary)
list_name
(JOIN)FAV_SHOPS
fav_id(primary)
shop_id(primary)
If I use a class Shop to represent shop entity, and FavShops to represent fav_shops, FavShops is written as below:
class FavShop {
int fav_id;
String list_name;
NSSet<Shop> shops;
}
Then how do I retrieve fav_shops from database in SQLite(Android)? I'll be appreciated if any one can provide some SQL statement, I also need to save the list to database, say, I added another shop to FavShop "My Favourites", how do I save it back to database?
Thanks!
You can use JOIN to get your FavShops table..
SELECT * FROM fav_shops INNER JOIN favourites_list ON fav_shops.fav_id = favourite_list.fav_id WHERE favourite_list.fav_id = <YOUR_LIST_ID>
You can put whatever clause you need in your WHERE (shop_id = ?, list_name = ?, etc..)
And to insert a new row in the fav_shops table
INSERT INTO fav_sops (fav_id, shop_id) values ('My Favourites', <A_SHOP_ID>);