Комната как моделировать Entity с вложенными коллекциями

Я пытаюсь реорганизовать некоторый код и перенести несколько архитектур для использования Room Database из компонентов архитектуры.

У меня есть такой объект, которым я часто пользуюсь, получая его из кеша. Вот как это выглядит:

public class LocationEvents {

private Map<NexoIdentifier, Date> mDeviceFirstSeenDates;

private ArrayDeque<LocationGeoEvent> mGeoEvents;
private ArrayDeque<LocationRSSIEvent> mRSSIEvents;
private Map<NexoIdentifier, ScoredLocationEvent> mHighestScores;

///Some methods

}

Я хочу смоделировать базу данных с этой структурой. Таким образом, будут такие объекты, как LocationGeoEvent, LocationRSSIEvent, ScoredLocationEvent.

Они выглядят так:

public class LocationGeoEvent {

private double mLongitude;
private double mLatitude;
private double mAccuracy;
private Date mTimestamp;
}

public class LocationRSSIEvent {

private int mRSSI;
private NexoIdentifier mNexoIdentifier;
private Date mTimestamp;
}

public class ScoredLocationEvent {

private float mScore;
private NexoIdentifier mNexoIdentifier;
private LocationRSSIEvent mLocationRSSIEvent;
private LocationGeoEvent mLocationGeoEvent;
private Date mScoreCalculatedTime;
private boolean mSent;
private boolean mPreviousSent;
}

NexoIdentifier - это простой POJO:

class NexoIdentifier {
abstract val partialSerialID: String
abstract val id: String
abstract val countryAndManufacturer: String
}

Так, как я могу сделать отношения, используя Комнату? Можно ли сделать объект LocationEvent как один раз? Так, например, я хочу иметь возможность получить LocationEvent со всем этим списком, которые вложены внутрь. Или, может быть, есть другой способ сделать это? Также не знаете точно, как смоделировать эти 2 карты внутри LocationEvents - DeviceFirstSeenDates и HighestScores - как два отдельных объекта по отношению к другим? А как именно? Я буду очень признателен за помощь в этом примере, я действительно застрял

ОБНОВИТЬ

@Entity(tableName = "location_events")
data class LocationEvents(
    @PrimaryKey(autoGenerate = true)
                 val id: Long = 0,
    @Embedded(prefix = "device") val mDeviceFirstSeenDates: Map<NexoIdentifier, Date> = HashMap(),
    @Embedded(prefix = "events") val mGeoEvents: ArrayDeque<LocationGeoEvent> = ArrayDeque(),
    val mRSSIEvents: ArrayDeque<LocationRSSIEvent> = ArrayDeque(),
    val mHighestScores: Map<NexoIdentifier, ScoredLocationEvent> = HashMap()
                 ) {
constructor() : this(0L, hashMapOf<NexoIdentifier, Date>(),
        ArrayDeque(), ArrayDeque(), hashMapOf<NexoIdentifier, ScoredLocationEvent>()
)

}

Ошибка: ошибка: у сущностей и Pojos должен быть общедоступный конструктор. Вы можете иметь пустой конструктор или конструктор, параметры которого соответствуют полям (по имени и типу).

1 ответ

Вы можете использовать Embedded. Если у вас одинаковые имена ваших переменных, вы хотите использовать префикс.

Пример:

public class LocationEvents {

@Embedded(prefix="device") private Map<NexoIdentifier, Date> mDeviceFirstSeenDates;
@Embedded(prefix="events") private ArrayDeque<LocationGeoEvent> mGeoEvents;
private ArrayDeque<LocationRSSIEvent> mRSSIEvents;
private Map<NexoIdentifier, ScoredLocationEvent> mHighestScores;
}

Или вы пишете конвертер для этого.

Пример:

public class DBConverters {
@TypeConverter
public static mapToString(Map<NexoIdentifier, Date value) {
    return value == null ? null : Gson.toJson(value);
}

@TypeConverter
public static Map<NexoIdentifier, Date> fromMap(String value) {
    return value == null ? null : Gson.fromJson(value, ...);
}
}

И аннотируйте свой конвертер в своем классе БД

@TypeConverters(DBConverters::class)
abstract class YourDb : RoomDatabase() { }

Обновление (после обновления вашего кода):

Предупреждение означает, что вам нужен как минимум один полезный конструктор. Чтобы решить эту проблему и разрешить использование классов "данных", необходимо использовать аннотацию игнорирования и позаботиться о том, чтобы у вас не было обнуляемых значений.

@Ignore constructor() : this(0L, hashMapOf<NexoIdentifier, Date>(),
        ArrayDeque(), ArrayDeque(), hashMapOf<NexoIdentifier, ScoredLocationEvent>()

Это гарантирует, что Room использует ваш конструктор, используемый в заголовке вашего класса.

Сама комната не имеет "настоящих" отношений, но вы можете создать "фиктивный класс", который содержит отношения. Room поддерживает ForeignKey, который позволяет вам определять поведение, если отношения обновляются или удаляются. Позаботьтесь о том, чтобы вы могли использовать встроенные только для других классов. Если есть неизвестные типы, такие как ваш HashMap, вы собираетесь написать конвертер.

Другие вопросы по тегам