I have a problem with a foreign key in ORMLite I have 2 classes QuestionDb and ResponsesDb which are the following :
public class ResponsesDb {
public static final String FIELD_ID = "id";
#DatabaseField(generatedId = true,columnName=FIELD_ID)
private int id;
#DatabaseField(canBeNull = false, foreign = true, foreignColumnName=QuestionDb.FIELD_REF)
private QuestionDb question;
#DatabaseField(canBeNull = false)
private String answer;
}
And :
#DatabaseTable(tableName = "question")
public class QuestionDb implements Serializable {
public static final String FIELD_REF = "ref";
private static final long serialVersionUID = 4106020204304605623L;
#DatabaseField(generatedId = true)
private int id;
#DatabaseField(canBeNull = false, unique = true, columnName=FIELD_REF, index=true)
private String ref;
#ForeignCollectionField(foreignFieldName = "question", eager = true)
private ForeignCollection<ResponsesDb> responses;
}
My problem is when i do that :
QueryBuilder<QuestionDb, Integer> questionQuery = helper
.getQuestionDao().queryBuilder();
QueryBuilder<ResponsesDb, Integer> responseQuery = helper
.getResponseDao().queryBuilder();
responseQuery = responseQuery.join(questionQuery);
I recieve that :
05-27 12:00:01.577: W/System.err(7272): java.sql.SQLException: Could not find a foreign class model.ormlite.tableClass.ResponsesDb field in class model.ormlite.tableClass.QuestionDb or vice versa
But if I remove the field foreignColumnName=QuestionDb.FIELD_REF from question field's annotation in ResponsesDb, the query works.
The fact is that as my program update the database, the id field can change so I want that the foreign key is ref. Do you have any idea how I can fix this problem ?
You can use a string as a foreign key. What you cannot do is define a foreign key with a foreignColumnName that is not the key of the other object.
From the example in the ORMLite documentation:
With foreign objects, just the id field from the Account is persisted
to the Order table as the column "account_id".
In this case, you have in QuestionDb:
#DatabaseField(generatedId = true)
private int id;
The generatedId annotation means that this is the id of the table. Having marked ref as unique will create a unique index, but it does not make it a candidate key. Thus it cannot be used as a foreign key from another table.
In short: if you need a string foreign key, then you can. Just define a string primary key in the referenced table. (i.e. remove the id field and put #DatabaseField(id = true) in the ref field.
Going further back, howerver, I don't understand why you claim:
The fact is that as my program update the database, the id field can
change
The generatedId value will not change for a row after inserting it. It's perfect for use as a foreign key! :)
Related
I'm defining table/field names thru usual annotations, like:
#DatabaseTable(tableName = "M")
public class Headers {
//android requires primary key as _ID
#DatabaseField(generatedId = true, columnName = "_ID", dataType = DataType.INTEGER_OBJ)
private Integer id;
#DatabaseField(
columnName = "MM2",
uniqueCombo = true,
canBeNull = true, //null means root folder
dataType = DataType.INTEGER_OBJ
)
private Integer parentId;
}
Meantime somewhere deep in my code, I need to make some queries, like:
QueryBuilder<Headers, Integer> qb = headersDao.queryBuilder();
qb.where().eq("_ID", headerId); //_ID field name
This kind of code looks ugly, since field name (in this case _ID) is hardcoded (even if would be declared as final static String)
Question: is it normal OrmLite coding practice? I'd be expecting that I could use instead of hardcoded _ID field some small code. For sure OrmLite "knows" all field names. Anyone can help me?
Define a constant for the field name, like
private static final String FIELD_ID = "_ID";
// Or make it public as Gray said into comment
public static final String FIELD_ID = "_ID";
and use it as like
//android requires primary key as _ID
#DatabaseField(generatedId = true, columnName = FIELD_ID, dataType = DataType.INTEGER_OBJ)
private Integer id;
And into your query
QueryBuilder<Headers, Integer> qb = headersDao.queryBuilder();
qb.where().eq(FIELD_ID, headerId); //_ID field name
If you look at documentation
They also follow the same
QueryBuilder<Account, String> qb = accountDao.queryBuilder();
Where where = qb.where();
// the name field must be equal to "foo"
where.eq(Account.NAME_FIELD_NAME, "foo");
// and
where.and();
// the password field must be equal to "_secret"
where.eq(Account.PASSWORD_FIELD_NAME, "_secret");
PreparedQuery<Account, String> preparedQuery = qb.prepareQuery();
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'm new to Android and I have problem with ORMLITE.
For example let's say I have this table:
#DatabaseTable(tableName = "accounts")
public class Account {
#DatabaseField(id = true)
private int id;
#DatabaseField(canBeNull = false)
private String name;
…
and I want to add new data into my table without setting id.
I tried this way:
#DatabaseTable(tableName = "accounts")
public class Account {
#DatabaseField(generatedId = true,allowGeneratedIdInsert=true)
private int id;
#DatabaseField(canBeNull = false)
private String name;
…
> Account acc = new Account();
>
> acc.setName("Example");
>
> AccountDao.createOrupdate(acc);
Here I can't insert acc into my database because acc id is zero. I want to generate id. Can I use autoincrement?
Here i can't insert acc into my database because acc id is zero. I want to generate id. Can i use autoincrement ?
So to quote the javadocs for the allowGeneratedIdInsert field in #DatabaseField:
If this is set to true then inserting an object with the ID field already set will not override it with a generated-id. This is useful when you have a table where items sometimes have IDs and sometimes need them generated. This only works if the database supports this behavior and if generatedId() is also true for the field.
So if you have acc.id set to a non-0 value, it should be inserted into the database with the id from acc. If you want acc to get an auto-generated id then you should just set acc.id to be 0.
For an example, you could take a look at the ORMLite Android test class. Search for the testCreateWithAllowGeneratedIdInsert() method which has code like:
AllowGeneratedIdInsert foo = new AllowGeneratedIdInsert();
assertEquals(1, dao.create(foo));
AllowGeneratedIdInsert result = dao.queryForId(foo.id);
assertEquals(foo.id, result.id);
...
AllowGeneratedIdInsert foo3 = new AllowGeneratedIdInsert();
foo3.id = 10002;
assertEquals(1, dao.create(foo3));
result = dao.queryForId(foo3.id);
assertEquals(foo3.id, result.id);
NOTE: the docs mention that this only works if the database supports it but Sqlite is one of those databases.
Use Wrapper class instead of int
#DatabaseField(id = true)
private Integer id;
When writing an instance of my data class to the database via ORMLite, and one of the child members (a foreign field) is null, I get back a non null child member.
Data classes as follows:
public class Site {
// snip
#DatabaseField(foreign = true, canBeNull = true)
private InstallationType installationType;
}
public class InstallationType {
#DatabaseField(generatedId = true)
private int id;
#DatabaseField
private String name;
}
When I read my instance of the Site class again via
getSiteDao().queryForId(id);
the installationType member is non null, but with a non-existent id. The only way the rest of our application can now work with this object, is if I manually do a lookup through the InstallationTypeDAO and set what I get back on the site. Query will sometimes return null as per the documentation.
Is there a way of getting ORMLite to set this member to null?
This was a bug in ORMLite that was fixed in version 4.15 (3/7/2011). Here's the change log file. What version are you using? Have you tried to update? Here's the bug report page:
Currently the following test passes so I think we have good coverage on that bug.
#Test
public void testForeignNull() throws Exception {
Dao<Foreign, Integer> dao = createDao(Foreign.class, true);
Foreign foreign = new Foreign();
foreign.foo = null;
assertEquals(1, dao.create(foreign));
Foreign foreign2 = dao.queryForId(foreign.id);
assertNotNull(foreign2);
assertNull(foreign2.foo);
}
With Foreign having the following fields:
#DatabaseField(generatedId = true)
public int id;
#DatabaseField(foreign = true)
public Foo foo;
If you are up to date in versions, please let me know if you can change the test to get it to fail.
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.