1

我尝试重构一些代码并移动几个架构以从架构组件中使用 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
}

那么如何使用 Room 建立关系呢?甚至可以将 LocationEvent 实体设为一次吗?因此,例如,我希望能够使用嵌套在其中的所有此列表来获取 LocationEvent。或者也许还有另一种方法可以做到这一点?也不知道如何将 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 必须有一个可用的公共构造函数。您可以有一个空的构造函数或参数与字段匹配的构造函数(按名称和类型)。

4

1 回答 1

4

您可以使用嵌入式。如果您的变量名称相同,则要使用前缀。

例子:

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 本身没有“真实”关系,但您可以创建一个包含关系的“虚拟类”。Room 支持 ForeignKey,如果关系更新或删除,您可以定义行为。请注意,您只能将嵌入式用于其他类。如果有像您的 HashMap 这样的未知类型,您将编写一个转换器。

于 2017-10-21T16:19:30.893 回答