I want to add an Attachment entity which I will be refering to from multiple different Entities, but it does not refer back to these, how do I get this working in ORMLite?
I keep getting this Exception:
Caused by: java.sql.SQLException: Foreign collection class entity.Attachment for
field 'attachments' column-name does not contain a foreign field named
'attachmentId' of class enity.News
For example I have a News Entity
#DatabaseTable
public class News extends Record {
#DatabaseField(index = true, id = true)
private long newsArticleId;
#DatabaseField
private String subject;
#DatabaseField
private String content;
#ForeignCollectionField
Collection<Attachment> attachments;
}
The Attachment Entity:
#DatabaseTable
public class Attachment extends Record {
#DatabaseField(id = true, index = true)
private long attachmentId;
#DatabaseField
private String attachmentUrl;
}
Could someone please point to me and laugh and tell me why I am doing this wrong and what I'm misunderstanding here. Thanks.
This is a FAQ. To quote from the ORMLite docs on foreign-collections:
Remember that when you have a ForeignCollection field, the class in the collection must (in this example Order) must have a foreign field for the class that has the collection (in this example Account). If Account has a foreign collection of Orders, then Order must have an Account foreign field. It is required so ORMLite can find the orders that match a particular account.
In your example, for ORMLite to figure out which Attachments a particular News entity has, the Attachment entity must have a News field. The other way to do would be to have a join table, but ORMLite won't do that for you.
Related
I have the following tables:
category:
id integer primary key autoincrement;
name text not null;
transaction:
id integer primary key autoincrement;
amount real not null;
category_id integer references category(id);
And have the following entity classes
class Category {
#PrimaryKey int cat_id;
String name;
}
class Transaction {
#PrimaryKey int tx_id;
double amount;
#ForeignKey(entity = Category.class, parentColumns = "category_id", childColumns = "cat_id")
int category_id;
#Embedded Category category;
}
When I run the following query, Transaction.category is always null
select t.* from transaction t JOIN category c ON t.category_id = c.cat_id
So far, most of the tutorials online don't show how to handle this situation. In fact, it also turns out room inserts the #Embedded fields.
How can I structure the entities to make sure a single query to retrieve transactions returns with related categories? The relationship is always one-to-one.
I'm using RxJava and do not want to do second queries. I would like to have a single query return everything because it's displayed in a ReycyclerView.
Thanks
Ok, so I found the answer from here: https://medium.com/androiddevelopers/database-relations-with-room-544ab95e4542 and https://developer.android.com/training/data-storage/room/relationships
So basically, the solution is to use the #Relation annotation , which can only be used on POJOs only as described here:
Please note this is for 1:1 relationships.
A one-to-one relationship between two entities is a relationship where
each instance of the parent entity corresponds to exactly one instance
of the child entity, and vice-versa.
For example, consider a music streaming app where the user has a
library of songs that they own. Each user has only one library, and
each library corresponds to exactly one user. Therefore, there should
be a one-to-one relationship between the User entity and the Library
entity.
First, create a class for each of your two entities. One of the
entities must include a variable that is a reference to the primary
key of the other entity.
#Entity
public class User {
#PrimaryKey public long userId;
public String name;
public int age;
}
#Entity
public class Library {
#PrimaryKey public long libraryId;
public long userOwnerId;
}
In order to query the list of users and corresponding libraries, you
must first model the one-to-one relationship between the two entities.
To do this, create a new data class where each instance holds an
instance of the parent entity and the corresponding instance of the
child entity. Add the #Relation annotation to the instance of the
child entity, with parentColumn set to the name of the primary key
column of the parent entity and entityColumn set to the name of the
column of the child entity that references the parent entity's primary
key.
public class UserAndLibrary {
#Embedded public User user;
#Relation(
parentColumn = "userId",
entityColumn = "userOwnerId"
)
public Library library;
}
Finally, add a method to the DAO class that returns all instances of
the data class that pairs the parent entity and the child entity. This
method requires Room to run two queries, so add the #Transaction
annotation to this method to ensure that the whole operation is
performed atomically.
#Transaction
#Query("SELECT * FROM User")
public List<UserAndLibrary> getUsersAndLibraries();
Let's say I have a Patient entity, storing the patient ID, a boolean and finally a Person object. So I annotate these fields with #ColumnInfo to store in the database.
Now a Person has 2 String fields: a first name and last name.
However, in my patients table, I want to have a column directly for the first name and last name fields (from Person), and so I want to be able to call e.g. firstName (and not having to call Person.firstName) from a query. How may I achieve this?
You can use #Embedded annotation of Room for it.
In your case it will be as follows
public class Person {
String firstName;
String lastName;
}
public class Patient {
int patientId;//just an assumption
#Embedded
Person person;
}
For more information check this
Note : I haven't provided other annotations like #ColumnInfo for brevity
Let's assume we have following entities:
Item:
class Item {
...
#Index(unique=true)
private String guid;
...
#ToMany
#JoinEntity(entity = JoinItemsWithTags.class, sourceProperty = "itemGuid", targetProperty = "tagName")
private List<Tag> tagsWithThisItem;
...
}
Tag:
class Tag {
#Id
private Long localId;
#Index(unique = true)
private String name;
...
}
and we need to join them. Here is my join entity class:
#Entity(nameInDb = "item_tag_relations")
class JoinItemsWithTags {
#Id
private Long id;
private String itemGuid;
private String tagName;
...
}
I want to use tag name as a join property instead of Long id, because it's easier to support consistency when syncing with server.
But currently tags getter in Item class always return an empty list. I've looked into log and found generated query which using internally in that getter:
SELECT * <<-- there were a long sequence of fields
FROM "tags" T JOIN item_tag_relations J1
ON T."_id"=J1."TAG_NAME" <<-- here is the problem, must be `T."NAME"=J1."TAG_NAME"`
WHERE J1."ITEM_GUID"=?
So the problem is that join is base on tag's _id field. Generated List<Tag> _queryItem_TagsWithThisItem(String itemGuid) method implicitly uses that id to make a join:
// this `join` nethod is overloaded and pass tag's id as source property
queryBuilder.join(JoinItemsWithTags.class, JoinItemsWithTagsDao.Properties.TagName)
.where(JoinItemsWithTagsDao.Properties.ItemGuid.eq(itemGuid));
Correct approach is this case might be following, I suppose:
// source property is passed explicitly
queryBuilder.join(/* Desired first parameter -->> */ TagDao.Properties.Name,
JoinItemsWithTags.class, JoinItemsWithTagsDao.Properties.TagName)
.where(JoinItemsWithTagsDao.Properties.ItemGuid.eq(itemGuid));
But this code is in generated dao, and I don't know how to do anything with it. Is there any way to workaround this?
I have a requirement where I need to store a List in a column in the database. Serializing the list might be an option, but i am not sure if it is the right one.
Also, i want to avoid creating another table to store the list elements and a reference to the original table row.
I am using ORMLite for the database operations.
Its a concept of foreign collection.
You need to create an entity that wraps the String. Something looks like:
#DatabaseTable
public class Student {
#DatabaseField(generatedId = true)
print int id;
#DatabaseField
private String fname;
#DatabaseField
private String lname;
#DatabaseField(foreign = true)
private Address address;
}
Then your Address class would have a ForeignCollection of these Student.
#DatabaseTable
public class Address {
#DatabaseField(generatedId = true)
print int id;
#ForeignCollectionField()
private ForeignCollection<Student> student;
}
Also refer this link , may it will help you.
I am not clever from ORMlite documentation. Is is possible to declare in class, that this parameter is foreign key?
e.g. I have table Customer:
#DatabaseTable(tableName = "customer")
public class Customer {
#DatabaseField(id = true)
private String customerName;
#DatabaseField
private String customerSurname;
#DatabaseField(foreign = true)
private String accountNameHolder;
#DatabaseField
private int age;
public Customer() {
}
}
AccountNameHolder should aim towards DatabaseField name from table Accounts. How to do that? I have found only parameter foreign = true, but there is nothing about, which parameter and from which table it represents.
Thanks
AccountNameHolder should aim towards DatabaseField name from table Accounts. How to do that?
I'm not exactly sure what you want but possibly you should change your foreign field to be the actual type instead of a name:
#DatabaseField(foreign = true)
private Account account;
Internally, ORMLite will store a account_id field (maybe the string name) in the Customer table but you don't have to worry about that. Remember that when you query for a Customer, the Account that is set on the account field will just have the id field set. To have ORMLite also lookup the account you will need to set the foreignAutoRefresh=true.
As #Lalit pointed out, here is some documentation on this subject. We've spent a long time on the documentation so it should be helpful.
Foreign objects
Foreign auto refresh
Also, there is some example code about foreign fields.
Hope this helps.