如何在 Room 2.3.0 中为我的实体添加外键?
How do I add a foreign key to my entity in Room 2.3.0?
我有一个使用 Room 2.2.5 的项目,我刚刚更新到版本 2.3.0 这是一个名为 photo 的实体的代码:
@Entity(tableName = Photo.TABLE_NAME, foreignKeys = @ForeignKey(entity = Event.class,
parentColumns = "_id",
childColumns = "id_event_ft",
onDelete = ForeignKey.CASCADE))
public class Photo {
public static final String TABLE_NAME = "Photo";
public static final String COLUMN_ID = BaseColumns._ID;
@PrimaryKey(autoGenerate = true)
@ColumnInfo(index = true, name = COLUMN_ID)
public Long id_photo;
@ColumnInfo(name = "path")
private String path;
@ForeignKey(entity = Event.class,
parentColumns = "_id",
childColumns = "id_event_ft",
onDelete = ForeignKey.CASCADE)
private Long id_event_ft;
public Photo(Long id_photo, String path, Long id_event_ft) {
this.id_photo = id_photo;
this.path = path;
this.id_event_ft = id_event_ft;
}
public Long getId_photo() {
return id_photo;
}
public void setId_photo(Long id_photo) {
this.id_photo = id_photo;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Long getId_event_ft() {
return id_event_ft;
}
public void setId_event_ft(Long id_event_ft) {
this.id_event_ft = id_event_ft;
}
}
现在我在尝试编译时遇到以下错误
error: annotation type not applicable to this kind of declaration
@ForeignKey(entity = Event.class, parentColumns = "_id", childColumns = "id_event_ft", onDelete = ForeignKey.CASCADE)
^
错误在变量上方的@ForeignKey中private Long id_event_ft;
在 documentation 我发现了这个:
Added missing target to @ForeignKey annotation preventing its usage outside of the @Entity annotation. (Iced1e)
显然不再允许在@Entity 注释之外使用@ForeignKey,但是如何将id_event_ft
变量绑定到外键?,如何为其赋值现在?
希望有人能帮帮我,非常感谢
关系
@多对一
如果关系是一个事件的多张照片,请使用 ORM Hibernate,这是在照片实体上定义外键约束的最简单方法
@ManyToOne
@JoinColumn(name = "id", nullable = false)
private Event id_event_ft;
使用 ForeignKey 不会自动(神奇地)建立关系。相反,它允许主要通过强制参照完整性来支持关系。
- 外键(关系)不需要外键定义。
它定义了一条规则,规定子列 (id_event_ft) 的值必须是存在于父列 ( _id)。如果存在外键冲突,它还支持处理(例如您使用的onDelete
)。
实际上提供 suitable 值是您必须以编程方式执行的操作,即添加照片的 id,您必须确定照片要 linked/related 到哪个事件。
您可以使用@Relation 来简化相关数据的提取。
所以请考虑以下几点:
一个事件 实体(对于演示来说很简单)
@Entity
public class Event {
@PrimaryKey(autoGenerate = true)
Long _id = null;
String other_columns;
public Event(){}
@Ignore
public Event(String other_columns) {
this.other_columns = other_columns;
}
}
- 照片的父列将是 _id 列。
- 第二个忽略(即被 Room 忽略)的构造函数,否则 Room 会发出警告,如 *warning: There are multiple good constructors and Room will pick the no-arg constructor. *
略有改动照片实体:-
@Entity(tableName = Photo.TABLE_NAME,
foreignKeys = @ForeignKey(
entity = Event.class,
parentColumns = "_id",
childColumns = "id_event_ft",
onDelete = ForeignKey.CASCADE),
indices = @Index("id_event_ft") //<<<<<<<<<< ADDED as Room warns if omitted
)
public class Photo {
public static final String TABLE_NAME = "Photo";
public static final String COLUMN_ID = BaseColumns._ID;
@PrimaryKey(autoGenerate = true)
@ColumnInfo(index = true, name = COLUMN_ID)
public Long id_photo;
@ColumnInfo(name = "path")
private String path;
/* <<<<<<<< COMMENTED OUT >>>>>>>>>>
@ForeignKey(entity = Event.class,
parentColumns = "_id",
childColumns = "id_event_ft",
onDelete = ForeignKey.CASCADE)
*/
private Long id_event_ft;
public Photo(Long id_photo, String path, Long id_event_ft) {
this.id_photo = id_photo;
this.path = path;
this.id_event_ft = id_event_ft;
}
public Long getId_photo() {
return id_photo;
}
public void setId_photo(Long id_photo) {
this.id_photo = id_photo;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Long getId_event_ft() {
return id_event_ft;
}
public void setId_event_ft(Long id_event_ft) {
this.id_event_ft = id_event_ft;
}
}
用于演示通过关系检索 POJO EventWithPhotos :-
public class EventWithPhotos {
@Embedded
Event event;
@Relation(entity = Photo.class,parentColumn = "_id",entityColumn = "id_event_ft")
List<Photo> photos;
}
Now a Dao AllDao:-
@Dao
interface AllDao {
@Insert
long insert(Event event);
@Insert
long insert(Photo photo);
@Transaction
@Query("SELECT * FROM event")
List<EventWithPhotos> getAllEventsWithPhotos();
}
How do I assign a value to it now?
现在举个例子,将所有内容放在一起,添加 2 个事件,第一个事件有 2 张照片,第二个事件有 1 照片。注意使用的不同技术:-
dao = db.getAllDao();
// Prepare to add an Event
Event newEvent = new Event();
newEvent.other_columns = "Event1";
// Add the Event retrieving the id (_id column)
long eventId = dao.insert(newEvent);
// Prepare a photo to be added to Event1
Photo newPhoto = new Photo(null,"photo1",eventId);
// Add the Photo to Event1
long photoid = dao.insert(newPhoto);
// Add second photo to Event 1 using the 2nd constructor
dao.insert(new Photo(null,"photo2",eventId));
// Add Event2 with a photo all in a single line (again using the 2nd constrcutor)
long event2Id;
dao.insert(new Photo(null,"photo3",event2Id = dao.insert(new Event("Event2"))));
// Get and output Each Event with the Photos for that Event
List<EventWithPhotos> allEventsWithPhotosList = dao.getAllEventsWithPhotos();
for (EventWithPhotos ewp: allEventsWithPhotosList) {
Log.d("EVENTPHOTOINFO","Event is " + ewp.event.other_columns);
for (Photo p: ewp.photos) {
Log.d("EVENTWITHPHOTO","\tPhoto is " + p.getPath() + " ID is " + p.getId_photo());
}
}
结果
当 运行 日志包含:-
D/EVENTPHOTOINFO: Event is Event1
D/EVENTWITHPHOTO: Photo is photo1 ID is 1
D/EVENTWITHPHOTO: Photo is photo2 ID is 2
D/EVENTPHOTOINFO: Event is Event2
D/EVENTWITHPHOTO: Photo is photo3 ID is 3
数据库(使用数据库检查器查看)显示:-
事件table:-
照片table:-
我有一个使用 Room 2.2.5 的项目,我刚刚更新到版本 2.3.0 这是一个名为 photo 的实体的代码:
@Entity(tableName = Photo.TABLE_NAME, foreignKeys = @ForeignKey(entity = Event.class,
parentColumns = "_id",
childColumns = "id_event_ft",
onDelete = ForeignKey.CASCADE))
public class Photo {
public static final String TABLE_NAME = "Photo";
public static final String COLUMN_ID = BaseColumns._ID;
@PrimaryKey(autoGenerate = true)
@ColumnInfo(index = true, name = COLUMN_ID)
public Long id_photo;
@ColumnInfo(name = "path")
private String path;
@ForeignKey(entity = Event.class,
parentColumns = "_id",
childColumns = "id_event_ft",
onDelete = ForeignKey.CASCADE)
private Long id_event_ft;
public Photo(Long id_photo, String path, Long id_event_ft) {
this.id_photo = id_photo;
this.path = path;
this.id_event_ft = id_event_ft;
}
public Long getId_photo() {
return id_photo;
}
public void setId_photo(Long id_photo) {
this.id_photo = id_photo;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Long getId_event_ft() {
return id_event_ft;
}
public void setId_event_ft(Long id_event_ft) {
this.id_event_ft = id_event_ft;
}
}
现在我在尝试编译时遇到以下错误
error: annotation type not applicable to this kind of declaration @ForeignKey(entity = Event.class, parentColumns = "_id", childColumns = "id_event_ft", onDelete = ForeignKey.CASCADE) ^
错误在变量上方的@ForeignKey中private Long id_event_ft;
在 documentation 我发现了这个:
Added missing target to @ForeignKey annotation preventing its usage outside of the @Entity annotation. (Iced1e)
显然不再允许在@Entity 注释之外使用@ForeignKey,但是如何将id_event_ft
变量绑定到外键?,如何为其赋值现在?
希望有人能帮帮我,非常感谢
关系
@多对一
如果关系是一个事件的多张照片,请使用 ORM Hibernate,这是在照片实体上定义外键约束的最简单方法
@ManyToOne
@JoinColumn(name = "id", nullable = false)
private Event id_event_ft;
使用 ForeignKey 不会自动(神奇地)建立关系。相反,它允许主要通过强制参照完整性来支持关系。
- 外键(关系)不需要外键定义。
它定义了一条规则,规定子列 (id_event_ft) 的值必须是存在于父列 ( _id)。如果存在外键冲突,它还支持处理(例如您使用的onDelete
)。
实际上提供 suitable 值是您必须以编程方式执行的操作,即添加照片的 id,您必须确定照片要 linked/related 到哪个事件。
您可以使用@Relation 来简化相关数据的提取。
所以请考虑以下几点:
一个事件 实体(对于演示来说很简单)
@Entity
public class Event {
@PrimaryKey(autoGenerate = true)
Long _id = null;
String other_columns;
public Event(){}
@Ignore
public Event(String other_columns) {
this.other_columns = other_columns;
}
}
- 照片的父列将是 _id 列。
- 第二个忽略(即被 Room 忽略)的构造函数,否则 Room 会发出警告,如 *warning: There are multiple good constructors and Room will pick the no-arg constructor. *
略有改动照片实体:-
@Entity(tableName = Photo.TABLE_NAME,
foreignKeys = @ForeignKey(
entity = Event.class,
parentColumns = "_id",
childColumns = "id_event_ft",
onDelete = ForeignKey.CASCADE),
indices = @Index("id_event_ft") //<<<<<<<<<< ADDED as Room warns if omitted
)
public class Photo {
public static final String TABLE_NAME = "Photo";
public static final String COLUMN_ID = BaseColumns._ID;
@PrimaryKey(autoGenerate = true)
@ColumnInfo(index = true, name = COLUMN_ID)
public Long id_photo;
@ColumnInfo(name = "path")
private String path;
/* <<<<<<<< COMMENTED OUT >>>>>>>>>>
@ForeignKey(entity = Event.class,
parentColumns = "_id",
childColumns = "id_event_ft",
onDelete = ForeignKey.CASCADE)
*/
private Long id_event_ft;
public Photo(Long id_photo, String path, Long id_event_ft) {
this.id_photo = id_photo;
this.path = path;
this.id_event_ft = id_event_ft;
}
public Long getId_photo() {
return id_photo;
}
public void setId_photo(Long id_photo) {
this.id_photo = id_photo;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Long getId_event_ft() {
return id_event_ft;
}
public void setId_event_ft(Long id_event_ft) {
this.id_event_ft = id_event_ft;
}
}
用于演示通过关系检索 POJO EventWithPhotos :-
public class EventWithPhotos {
@Embedded
Event event;
@Relation(entity = Photo.class,parentColumn = "_id",entityColumn = "id_event_ft")
List<Photo> photos;
}
Now a Dao AllDao:-
@Dao
interface AllDao {
@Insert
long insert(Event event);
@Insert
long insert(Photo photo);
@Transaction
@Query("SELECT * FROM event")
List<EventWithPhotos> getAllEventsWithPhotos();
}
How do I assign a value to it now?
现在举个例子,将所有内容放在一起,添加 2 个事件,第一个事件有 2 张照片,第二个事件有 1 照片。注意使用的不同技术:-
dao = db.getAllDao();
// Prepare to add an Event
Event newEvent = new Event();
newEvent.other_columns = "Event1";
// Add the Event retrieving the id (_id column)
long eventId = dao.insert(newEvent);
// Prepare a photo to be added to Event1
Photo newPhoto = new Photo(null,"photo1",eventId);
// Add the Photo to Event1
long photoid = dao.insert(newPhoto);
// Add second photo to Event 1 using the 2nd constructor
dao.insert(new Photo(null,"photo2",eventId));
// Add Event2 with a photo all in a single line (again using the 2nd constrcutor)
long event2Id;
dao.insert(new Photo(null,"photo3",event2Id = dao.insert(new Event("Event2"))));
// Get and output Each Event with the Photos for that Event
List<EventWithPhotos> allEventsWithPhotosList = dao.getAllEventsWithPhotos();
for (EventWithPhotos ewp: allEventsWithPhotosList) {
Log.d("EVENTPHOTOINFO","Event is " + ewp.event.other_columns);
for (Photo p: ewp.photos) {
Log.d("EVENTWITHPHOTO","\tPhoto is " + p.getPath() + " ID is " + p.getId_photo());
}
}
结果
当 运行 日志包含:-
D/EVENTPHOTOINFO: Event is Event1
D/EVENTWITHPHOTO: Photo is photo1 ID is 1
D/EVENTWITHPHOTO: Photo is photo2 ID is 2
D/EVENTPHOTOINFO: Event is Event2
D/EVENTWITHPHOTO: Photo is photo3 ID is 3
数据库(使用数据库检查器查看)显示:-
事件table:-
照片table:-