【问题标题】:Room how to model Entity with nested collectionsRoom 如何使用嵌套集合对实体建模
【发布时间】:2017-10-21 16:14:47
【问题描述】:

我尝试重构一些代码并移动几个架构以从架构组件中使用 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 必须有一个可用的公共构造函数。你可以有一个空的构造函数或一个参数匹配字段(按名称和类型)的构造函数。

【问题讨论】:

    标签: android android-database android-room android-orm


    【解决方案1】:

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

    例子:

    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 使用您在类头中使用的构造函数。

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

    【讨论】:

    • 谢谢,但你能看看我的更新吗?我忘了提到我正在使用 Kotlin。我有一个没有构造函数的错误,但它存在
    • 当然,等等。启动 AS
    猜你喜欢
    • 2011-10-20
    • 2011-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多