Это разъяснение моего предыдущего вопроса Как использовать Android Room для сущностей без полей?.
Мой вариант использования заключается в том, что я использую библиотеку Java JAR, предоставленную третьей стороной, которая содержит множество POJO, которые я хочу хранить и извлекать через Android Room. Ясно, что я не могу аннотировать поля в классе, для которого у меня нет исходного кода. Внутренняя структура предоставленных POJO представляет собой черный ящик, все, к чему у меня есть доступ, — это сеттеры и геттеры.
Представьте, например, что я хочу использовать экземпляры android.graphics.Rect
с комнатой.
Можно ли определить состояние POJO через геттеры? Иными словами, если бы вы использовали геттеры для установки атрибутов другого экземпляра объекта, были бы эти два объекта фактически одинаковыми?
@Synergi Правильно, в библиотеке POJO есть сеттеры и геттеры, и нет другого открытого состояния.
@satur9nine Я полагаю, что в случае, который вы описываете, лучшим способом действий будет написание объекта модели объекта, который представляет POJO, который вы хотите сохранить, значениями из его сеттеров и служебной функцией для сопоставления вашего объекта объекта Room обратно с библиотека POJO. В противном случае единственный другой вариант, о котором я могу думать сейчас, - это ответ Бланделла.
Взгляните на встроенную аннотацию
https://developer.android.com/reference/android/arch/persistence/room/Встроенный
Can be used as an annotation on a field of an Entity or Pojo to signal that nested fields (i.e. fields of the annotated field's class) can be referenced directly in the SQL queries.
Библиотека:
class BlackBox {
String foo
}
Ваш код:
@Entity
class MyWhiteBox {
@Embedded
private BlackBox blackbox
}
Room будет рассматривать foo
так, как будто это поле класса MyWhiteBox
при сопоставлении строки SQLite с адресом.
Это совсем не работает для меня. Я не хочу, чтобы Room рассматривал библиотеку POJO как встроенную в POJO, которую я пишу сам. В вашем примере MyWhiteBox
нужен первичный ключ, чтобы сделать комнату счастливой, но я не хочу добавлять дополнительные поля в библиотеку POJO, я просто хочу использовать геттеры и сеттеры, которые есть в библиотеке POJO, для различных столбцов, включая первичный ключ, который у меня нет не хочу добавлять дополнительные столбцы.
если ваш первичный ключ контролируется библиотекой/другим модулем, который не знает, что он используется в качестве первичного ключа базы данных, это приведет к очень связанному/глючному/недетерминированному (не чистому!) коду. Укусите пулю и обработайте свои собственные POJO для своей собственной базы данных. Или используйте аннотации в модуле библиотеки.
Если бы я мог каким-то образом добавить свой собственный идентификатор в POJO библиотеки, это было бы приемлемо (обертывание, создание подклассов или что-то еще)? Самое главное, мне нужен способ контролировать, какие поля хранятся или нет в POJO библиотеки, не имея возможности аннотировать POJO библиотеки.
Вот решения, которые я придумал, ни одно из них не является полностью идеальным, но последнее достойно.
Плохой:
Эта опция просто наивно делает копию класса POJO библиотеки и предоставляет вспомогательные методы для преобразования POJO библиотеки в POJO комнаты и обратно. Довольно некрасиво, и поскольку это создает копии, которые могут расходиться и рассинхронизироваться, мне приходится писать много кода, копирующего туда и обратно в моем приложении.
@Entity(tableName = "items")
public class RoomItem {
@PrimaryKey
@NonNull
public String id;
public String name;
public Long price
public LibraryItem to() {
LibraryItem li = new LibraryItem();
li.setName(name);
li.setPrice(price);
}
public static RoomItem from(LibraryItem li) {
RoomItem ri = new RoomItem();
ri.name = li.getName();
ri.price = li.getPrice();
}
}
Хорошо:
В этом случае RoomItem
— это класс-оболочка с полями, которые используются только для информирования Room о столбцах и типах, кроме id
в полях фактически ничего не хранится, поэтому они просто тратят место. Каждый раз, когда я хочу получить настоящий библиотечный объект для использования с библиотечными методами, я должен захватить обернутый экземпляр. По крайней мере, RoomItem и LibraryItem фактически отражают изменения.
@Entity(tableName = "items")
public class RoomItem {
// I have to put these fields here even though they aren't used to store any
// data just to make Room happy!
@PrimaryKey
@NonNull
private String id = "";
private String name;
private Long price;
@Ignore
private final LibraryItem item = new LibraryItem();
public RoomItem(String id, String name, Long price) {
this.id = id;
setName(name);
setPrice(price);
}
@NonNull
public String getId() {
return id;
}
public void setId(@NonNull String id) {
this.id = id;
}
public String getName() {
return item.getName();
}
public void setName(String name) {
item.setName(name);
}
public Long getPrice() {
return item.getPrice();
}
public void setPrice(Long price) {
item.setPrice(price);
}
public Library getLibraryItem() {
return item;
}
}
Лучше (2.2.0-alpha02 или новее)
Гугл исправил ошибку, о котором я сообщил в Room, и начиная с версии 2.2.0-alpha02 теперь можно использовать наследование. Поля в дочернем классе просто используются для информирования Room о том, что нужно сохранить, и когда minify
включен, они фактически отбраковываются, поэтому память не тратится впустую. Это решение потребовало от меня немного знаний о внутренней структуре родительского класса, чтобы я мог игнорировать вещи внутри него, такие как privateParentField
. Однако это лучше, чем пример «Хорошо», потому что теперь я могу передавать экземпляры RoomItem
методам, которые принимают LibraryItem
, и мне не нужно писать много шаблонного кода.
@Entity(tableName = "items", ignoredColumns = "privateParentField")
public class RoomItem extends LibraryItem {
// I have to put these fields here even though they aren't used to store any
// data just to make Room happy!
@PrimaryKey
@NonNull
private String id;
private String name;
private Long price;
public RoomItem(String id, String name, Long price) {
setId(id);
setName(name);
setPrice(price);
}
}
Я обновил ответ, включив в него последнее исправление от Google в 2.2.0-alpha02, о котором я сообщил в ответ на свои проблемы.
Хорошо, вы упомянули два класса - POJO и ROOM? Я хотел бы сравнить их. Я получаю такую ошибку: error: Field has non-unique column name.
.
@deadfish POJO — это аббревиатура от «простой старый класс Java». Обычно это означает обычный класс Java, который не расширяет другой класс. Room — это не класс, это название программной библиотеки, написанной Google, см. здесь: developer.android.com/training/data-storage/room
Привет, я понимаю основы, но я хотел бы проверить упомянутые вами классы (или я что-то неправильно понял). Было бы здорово, если бы я мог использовать один класс вместо двух (pojo и room), когда я работаю с ними, особенно когда я загружаю pojo, а затем я должен вставить в базу данных. Может быть, у вас есть другой пример по сути?
Оберните каждый из исходных POJO в новый POJO, содержащий необходимые аннотации.