简体   繁体   中英

Room how to model Entity with nested collections

I try to refactor some code and move several architecture to use Room Database from architecture components.

I have such object, which i use often, getting it from cache. Here what it looks like:

public class LocationEvents {

private Map<NexoIdentifier, Date> mDeviceFirstSeenDates;

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

///Some methods

}

I want to model database with this structure. So there will be entities like LocationGeoEvent, LocationRSSIEvent, ScoredLocationEvent.

They look like this:

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 is a simple POJO:

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

So how can i make the relations using Room? Is it even possible to make the LocationEvent entity as once? So for example i want to be able to fetch LocationEvent with all of this list that are nested inside. Or maybe there is another way to do this? Also don't know exactly how to model those 2 maps inside LocationEvents - DeviceFirstSeenDates, and HighestScores - as two separate Entities with relation to others? But how exactly? I will really appreciate help in this example, I am really stuck

UPDATE

@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>()
)

}

Error:error: Entities and Pojos must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type).

You can either use Embedded. If you have same names of your variables you want to use prefix.

Example:

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;
}

Or you write a Converter for that.

Example:

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, ...);
}
}

And annotate your Converter in your DB class

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

Update (after your code update):

The warning means that you need at least one useable constructor. To solve that and still allow "data" classes you need to use ignore annotation and take care that you dont have any nullable values.

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

That will make sure that Room uses your constructor used in the header of your class.

Room itself has no "real" relationships , but you can create a "dummy class" which holds relationships. Room supports ForeignKey which let you define a behaviour if a relationship gets updated or deleted. Take care that you can only use embedded for other classes. If there are unknown types like your HashMap you'r going to write a converter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM