Android Persistence room: "Невозможно понять, как читать это поле из курсора"
Я пытаюсь создать связь между двумя таблицами базы данных, используя новую библиотеку Android Persistence Room Library. Я просмотрел документацию и попытался реализовать пример, найденный в https://developer.android.com/reference/android/arch/persistence/room/Relation.html:
@Entity
public class User {
@PrimaryKey
int id;
}
@Entity
public class Pet {
@PrimaryKey
int id;
int userId;
String name;
}
@Dao
public interface UserDao {
@Query("SELECT * from User")
public List<User> loadUser();
}
@Dao
public interface PetDao {
@Query("SELECT * from Pet")
public List<Pet> loadUserAndPets();
}
public class UserAllPets {
@Embedded
public User user;
@Relation(parentColumn = "user.id", entityColumn = "userId", entity = Pet.class)
public List pets;
}
@Dao
public interface UserPetDao {
@Query("SELECT * from User")
public List<UserAllPets> loadUserAndPets();
}
Я получаю следующую ошибку
...error: Cannot figure out how to read this field from a cursor.
по отношению к:
private java.util.List<?> pets;
Я хотел бы указать, что некоторые вещи в их документах действительно сбивают с толку. Например, отсутствие @PrimaryKey
, а также тот факт, что класс User
отсутствует аннотация @Entity
, хотя он должен быть сущностью (как, как я вижу). Кто-нибудь сталкивался с одной и той же проблемой? Большое спасибо заранее
Ответы
Ответ 1
Документ действительно запутан. Попробуйте чуть ниже классов:
1) Пользовательский объект:
@Entity
public class User {
@PrimaryKey
public int id; // User id
}
2) Entity Pet:
@Entity
public class Pet {
@PrimaryKey
public int id; // Pet id
public int userId; // User id
public String name;
}
![введите описание изображения здесь]()
3) UserWithPets POJO:
// Note: No annotation required at this class definition.
public class UserWithPets {
@Embedded
public User user;
@Relation(parentColumn = "id", entityColumn = "userId", entity = Pet.class)
public List<Pet> pets; // or use simply 'List pets;'
/* Alternatively you can use projection to fetch a specific column (i.e. only name of the pets) from related Pet table. You can uncomment and try below;
@Relation(parentColumn = "id", entityColumn = "userId", entity = Pet.class, projection = "name")
public List<String> pets;
*/
}
-
parentColumn
относится к столбцу Embedded User
table id
,
-
entityColumn
относится к столбцу Pet
table userId
(User
- Pet
),
-
entity
относится к таблице (Pet
), которая имеет отношение к таблице User
.
4) UserDao Dao:
@Dao
public interface UserDao {
@Query("SELECT * FROM User")
public List<UserWithPets> loadUsersWithPets();
}
Теперь попробуйте loadUsersWithPets()
, который возвращает пользователей с их списком домашних животных.
Изменить: См. мой другой ответ для многих отношений.
Ответ 2
Я знал это немного не по теме, но я надеюсь, что мой ответ может предоставить действительную альтернативу. Я создаю библиотеку Kripton Persistente Library, библиотеку с открытым исходным кодом для платформы Android с целью единообразного решения задачи сохранения: SQlite, REST-сервис (через дооснащение), общие настройки и файл. Он использует обработчик аннотации для генерации кода и исключения кода шаблона.
Я адаптирую свои классы для работы с Kripton.
Объекты сохранения:
@BindType
public class Pet {
public long id;
@BindColumn(foreignKey = User.class)
public long userId;
public String name;
}
@BindType
public class User {
public long id;
@BindColumn(enabled=false)
public List<Pet> pets;
}
Объявление DAO и Datasource:
@BindDao(Pet.class)
public interface PetDao {
@BindSqlSelect
public List<Pet> loadPet();
}
@BindDao(User.class)
public interface UserDao {
@BindSqlSelect
public List<User> loadUser();
}
@BindDataSource(dao = { UserDao.class, PetDao.class }, fileName = "pet.db")
public interface PetUserDataSource {
}
Для пользователей Pet и User Kripton генерирует две таблицы со следующим DDL:
CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT);
CREATE TABLE pet (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, name TEXT, FOREIGN KEY(user_id) REFERENCES user(id));
И, наконец, код для вызова операции SQL на источнике данных:
...
BindPetUserDataSource dataSource=BindPetUserDataSource.instance();
dataSource.openReadOnlyDatabase();
dataSource.getUserDao().loadUser();
// to load a pet starting from a user just add userId to method
dataSource.getPetDao().loadPet();
dataSource.close();
...
Основное отличие заключается в том, что Kripton работает просто над объектами: отношения могут быть определены как внешний ключ, но я выбрал, чтобы избежать их управления.
Для получения дополнительной информации: