How can i create one-to-many relation with the table itself in ormlite? I have a class that holds collection of itself. I don't know how to map this class.
#DatabaseTable(tableName = "USER")
public class User {
#DatabaseField(generatedId = true)
private long id;
#DatabaseField
private String username;
#ForeignCollectionField
private ForeignCollection<User> friends;
...
Thanks in advance.
I have a class that holds collection of itself. I don't know how to map this class.
I think the best way would be to define a UserFriend entity that has a reference to the owner User, friend User, and an id. Something like:
#DatabaseTable(tableName = "USERFRIEND")
public class UserFriend {
#DatabaseField(generatedId = true)
private long id;
// corresponds to the user who has the friend
#DatabaseField(foreign = true)
private User user;
// corresponds to the friend of the user
#DatabaseField(foreign = true)
private User friend;
...
Then your foreign collection becomes:
#ForeignCollectionField(foreignFieldName = 'user')
private ForeignCollection<UserFriend> friends;
Notice the foreignFieldName which has to point to the user so the user's friends can be found.
Related
I am quite familiar with these kind of thing on Spring JPA but I can not make it work on Android. I post my code below so you can understand the question better. I have two classes and a third class that needs to contain objects of class 1 and 2. I know that the code for the third class is not correct, since Room does not support object references like that. If I save just the id-s of the objects as foreign keys I am not able to query after the results.
There must be some kind of nice solution for this problem. Thank you.
#Entity(tableName = "soup")
public class Soup {
#PrimaryKey(autoGenerate = true)
private long id;
private String name;
// getter and setters
}
#Entity(tableName = "main_course")
public class MainCourse {
#PrimaryKey(autoGenerate = true)
private long id;
private String name;
// getter and setters
}
#Entity(tableName = "menu")
public class Menu {
#PrimaryKey(autoGenerate = true)
private long id;
private Soup soupOptionOne;
private Soup soupOptionTwo;
private Soup soupOptionThree;
private MainCourse courseOptionOne;
private MainCourse courseOptionTwo;
private MainCourse courseOptionThree;
}
I am using ActiveAndroid and have two models:
#Table(name = "Topics")
public class Topic extends Model {
#Column(name = "Name") String name;
#SerializedName("id")
#Column(index = true,
unique = true,
onUniqueConflict = Column.ConflictAction.REPLACE) public long topic_id;
#Column(name = "Counts",
onUpdate = Column.ForeignKeyAction.CASCADE,
onDelete = Column.ForeignKeyAction.CASCADE) Counts counts;
}
and
#Table(name = "Counts")
public class Counts extends Model {
#Column(name = "Users") int users;
}
Constructors have been excluded for brevity.
Now, when i save Topic, I expect the Counts to be saved. But it does not.
I am using gson to create the models from json. Any reason why counts are not being loaded?
First you have to call count.save() then you can call topic.save(). ActiveAndroid needs the id to get the reference and that happen when you save it.
I have one to many relationship in local database. I am using ORMLite technology and my foreign object for one part is configured with foreignAutoRefresh = false.
#DatabaseTable(tableName = "Person")
public class Person{
#DatabaseField(generatedId = true)
private long id;
#DatabaseField
private String name;
#ForeignCollectionField
private Collection<Account> accounts;
}
Account:
#DatabaseTable(tableName = "Account")
public class Account{
#DatabaseField(generatedId = true)
private long id;
#DatabaseField
private String userName;
#DatabaseField(foreign = true, columnName =
"person_Id", foreignAutoRefresh = false)
private Person person;
}
List personList = personRuntimeDao.queryForAll();
The problem is that when ORMLite fetch the List with persons in the accounts for each person the foreign object is fetched too. And because that it leads to infinite recursion. There is no exception in the fetching but when I try to parse this List to Gson it throws me an exception - StackOverFlow because the List is infinite. When I read for foreignAutoRefresh I understand that when is configured to false, the foreign object needs to be NULL but it is not.
Is there anyone which could help me with this issue?
I have in my model Class
List<String> _photo_array;
since I can put anotation on String Class is it a way to persist it using ormLite?
since I can put anotation on String Class is it a way to persist it using ormLite?
You are going to have to create an entity that wraps the String. Something like:
#DatabaseTable
public class Photo {
#DatabaseField(generatedId = true)
private int id;
#DatabaseField
private String photo;
#DatabaseField(foreign = true)
private Model model;
}
Then your model class would have a ForeignCollection of these photos.
#DatabaseTable
public class Model {
#DatabaseField(generatedId = true)
private int id;
#ForeignCollectionField()
private ForeignCollection<Photo> photos;
}
See the foreign collection example.
One way to solve this problem is to use one-to-many relations.
To persist one-to-many relations you can should use ForeignCollection.
Check the docu.
Other types of collections are not supported by ORMLite, as I know.
Another point is you need a back-reference in the referenced Object.
To mark a field as back-reference, use annotation #DatabaseField(foreign = true, ... )
For Scenario A(1) -> B(n)
class A {
#DatabaseField(generatedId = true, columnName = BaseColumns._ID)
public int _id;
#ForeignCollectionField(eager = true)
public ForeignCollection<B> _photo_array;
}
class B {
#DatabaseField(generatedId = true, columnName = BaseColumns._ID)
public int _id;
#DatabaseField(foreign = true, canBeNull = false,
foreignAutoRefresh = true, foreignAutoCreate = true)
public A a;
}
In this scenario A reference B in one-to-many way. If a will be loaded, all dependent B's will also be loaded (because of eager = true)
To save this structure you could use this way (i hope you have allready created ADao and BDao classes):
final A a = ...;
final ADao aDAO = ...;
aDAO.createOrUpdate(a);
final ArrayList<B> children = ...;
final BDao bDAO = ...;
for (final B b: children ) {
bDAO.create(season);
}
A and B including dependency will be stored. If you now try to get A from db you will also get all B's related to instance of A.
Is it possible to cache nested (2-3 level of nesting) objects (foreign fields) via Robospice/ORMlite?
https://groups.google.com/forum/#!msg/robospice/VGLB3-vM3Ug/-piOac212HYJ - there you can read that is possible, but unfortunatelly I can't achieve it.
Here is my source code:
#DatabaseTable(tableName = "city")
#JsonIgnoreProperties(ignoreUnknown = true)
public class City {
#DatabaseField(id = true)
#JsonProperty("id")
private long id;
#DatabaseField
#JsonProperty("name")
private String name;
#ForeignCollectionField(eager = true, maxEagerLevel = 3)
#JsonProperty("clubs")
private Collection<Club> clubs;
...
#DatabaseTable(tableName = "club")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Club {
#DatabaseField(id = true)
#JsonProperty("user_id")
private long id;
#DatabaseField
#JsonProperty("name")
private String name;
#DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = "city_id", maxForeignAutoRefreshLevel = 2)
private City city;
#DatabaseField(foreign = true)
#JsonProperty("address")
private VenueAddress address;
...
#DatabaseTable(tableName = "address")
#JsonIgnoreProperties(ignoreUnknown = true)
public class VenueAddress {
#DatabaseField(id = true)
#JsonProperty("uid")
private long id;
#DatabaseField
#JsonProperty("street")
private String street;
#DatabaseField
#JsonProperty("street_number")
private String streetNumber;
#DatabaseField
#JsonProperty("country")
private String country;
#DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = "club_id", maxForeignAutoRefreshLevel = 2)
private Club club;
...
And sample SpiceService:
public class SampleSpiceService extends SpringAndroidSpiceService {
private static final int WEBSERVICES_TIMEOUT = 10000;
#Override
public CacheManager createCacheManager(Application application) {
CacheManager cacheManager = new CacheManager();
List<Class<?>> classCollection = new ArrayList<Class<?>>();
// add persisted classes to class collection
classCollection.add(VenueAddress.class);
classCollection.add(City.class);
classCollection.add(Club.class);
// init
RoboSpiceDatabaseHelper databaseHelper = new RoboSpiceDatabaseHelper(application,
"sample_database.db", 5);
InDatabaseObjectPersisterFactory inDatabaseObjectPersisterFactory = new InDatabaseObjectPersisterFactory(
application, databaseHelper, classCollection);
cacheManager.addPersister(inDatabaseObjectPersisterFactory);
return cacheManager;
}
#Override
public RestTemplate createRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
// set timeout for requests
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setReadTimeout(WEBSERVICES_TIMEOUT);
httpRequestFactory.setConnectTimeout(WEBSERVICES_TIMEOUT);
restTemplate.setRequestFactory(httpRequestFactory);
MappingJacksonHttpMessageConverter messageConverter = new MappingJacksonHttpMessageConverter();
restTemplate.getMessageConverters().add(messageConverter);
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
return restTemplate;
}
}
And when I fetch City object from cache it has clubs collection, but VenueAddress in each Club has null fields (except id).
Do you have any advices?
This is more a ORM Lite question than a RoboSpice thing.
Maybe you could "embed" the address data inside the club entitiy/table.
This thread might be of interest :
one-to-one relationship in Ormlite
The problem may come from here as stated in ormlite docs :
foreignAutoRefresh
Set this to be true (default false) to have a foreign field automagically refreshed when an object is queried. The default is to just have the ID field in the object retrieved and for the caller to call refresh on the correct DAO. If this is set to true then, when the object is queried, a separate database call will be made to load of the fields of the foreign object via an internal DAO. NOTE: this will not automagically create the foreign object if you create an object that has this field set.
NOTE: This will create another DAO object internally so low memory devices may want to call refresh by hand.
NOTE: To protect against recursion, there are a couple of places were auto-refreshing has been limited. If you are auto-refreshing a class that itself has field with foreignAutoRefresh set to true or if you are auto-refreshing a class with a foreign collection, in both cases the resulting field will be set to null and not auto-refreshed. You can always call refresh on the field directly if you need it.