Android 房间 - CASCADE 依赖于 table 用于 DELETE 并保持 INSERT 操作不可触及?
Android Room - CASCADE in dependent table for DELETE and keep untouchable for INSERT operation?
我有两个 tables - users
和 conversations
。许多 users
可能参加一个 conversation
,一个 user
可能是许多 conversations
的成员
@Entity(tableName = "users")
public class User {
@NonNull
@PrimaryKey
@ColumnInfo(name = "userId")
private String id;
...
//Getters and setters
}
@Entity(tableName = "conversations")
public class Conversation {
@NonNull
@PrimaryKey
@ColumnInfo(name = "uuid")
private String id;
...
//Getters and setters
}
追踪哪个user
参与哪个conversation
我用第三个table:
@Entity(tableName = "user_conversation", indices = {@Index(value = {"userId", "conversationUuid"}, unique = true)},
primaryKeys = {"userId", "conversationUuid"},
foreignKeys = {
@ForeignKey(onDelete = CASCADE, entity = User.class, parentColumns = "userId", childColumns = "userId"),
@ForeignKey(onDelete = CASCADE, entity = Conversation.class, parentColumns = "uuid", childColumns = "conversationUuid")
})
public class JoinUserConversation {
@NonNull
private String userId;
@NonNull
private String conversationUuid;
...
//Getters and setters
}
Dao
个对象:
@Dao
public interface UsersDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(User user);
...
}
@Dao
public interface ConversationsDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
long insert(Conversation conversation);
....
}
当我从他们的 table 中 delete
一个 user
或 conversation
时,我也需要从 user_conversation
中删除它们,我使用 onDelete = CASCADE
用于此目的。但是当我insert
一个user
或conversation
到他们table的时候我不需要删除 他们来自 user_conversation
。但据我了解,如果插入实体已经存在于 table 和相应的 user
或 [=18= 中,则 insert
和 @Insert(onConflict = OnConflictStrategy.REPLACE)
将通过 delete
执行] 将从 user_conversation
table 中删除。 如何防止 user_conversation
在 insert
上发生变化?
我相信您可以通过检查要插入的行的 ID 来完成您想要的操作,如果存在则更新,如果不存在则插入。
- 请注意,我尝试将
deferred = true
与 @Transaction
一起使用,但由于 CASCADE 执行了它应该执行的操作,所以没有冲突。
例如,对于用户:-
添加
@Query("SELECT count() FROM users WHERE userId = :userId")
int getUserCount(String userId);
和
@Update()
int updateUser(User user);
然后有个方法,比如:-
private void upsertUser(User u) {
if (mWTDao.getUserCount(u.getId()) > 0) {
mWTDao.updateUser(u);
} else {
mWTDao.insert(u);
}
}
- mWTDao 是所有 Dao 存在的地方(示例相同)
例子
考虑以下摘录(来自测试代码):-
......... other code
upsertUser(new User("userid001","Fred"));
upsertUser(new User("userid002","Mary"));
upsertUser(new User("userid003","Jane"));
upsertUser(new User("userid004","Tom"));
mWTDao.insert( new Conversation("c001","SUBJECT A"));
mWTDao.insert( new Conversation("c002","SUBJECT X"));
mWTDao.insert(new JoinUserConversation("userid001","c001"));
mWTDao.insert(new JoinUserConversation("userid003","c001"));
mWTDao.insert(new JoinUserConversation("userid002","c002"));
mWTDao.insert(new JoinUserConversation("userid004","c002"));
logAllInfo("PRE");
upsertUser(new User("userid001","Harry"));
upsertUser(new User("userid002","Gertrude"));
logAllInfo("POST");
}
private void upsertUser(User u) {
if (mWTDao.getUserCount(u.getId()) > 0) {
mWTDao.updateUser(u);
} else {
mWTDao.insert(u);
}
}
private void logAllInfo(String tag) {
Log.d("INFO" + tag,"Logging Conversations via Original Mapping Table ");
for (JoinUserConversation juc: mWTDao.getAllJUC()) {
Conversation c = mWTDao.getConversation(juc.getConversationUuid());
User u = mWTDao.getUser(juc.getUserId());
Log.d("INFO" + tag,"\tFor Conversation " + c.getTitle() + "ID is (" + c.getId() + ") User is " + u.getName() + " ID is (" + u.getId() + ")");
}
Log.d("MAPINFO" + tag,"Logging Users ");
for (User u: mWTDao.getAllUsers()) {
Log.d("USERINFO" + tag,"\tID is " + u.getId() + " Name is " + u.getName());
}
Log.d("CONVINFO","Logging Conversations");
for (Conversation c: mWTDao.getAllConversations()) {
Log.d("CONVINFO" + tag,"\tID is " + c.getId() + " Ttitle is " + c.getTitle());
}
}
- 这会添加 4 个用户(使用 upsertUser 方法)和 2 个对话以及一些 user_conversations
- 显示信息
- 然后尝试使用 upsertUser 方法添加现有用户
- 再次显示信息,显示现有用户已更新。
结果
2019-09-18 08:14:19.214 D/INFOPRE: Logging Conversations via Original Mapping Table
2019-09-18 08:14:19.220 D/INFOPRE: For Conversation SUBJECT AID is (c001) User is Fred ID is (userid001)
2019-09-18 08:14:19.222 D/INFOPRE: For Conversation SUBJECT AID is (c001) User is Jane ID is (userid003)
2019-09-18 08:14:19.224 D/INFOPRE: For Conversation SUBJECT XID is (c002) User is Mary ID is (userid002)
2019-09-18 08:14:19.226 D/INFOPRE: For Conversation SUBJECT XID is (c002) User is Tom ID is (userid004)
2019-09-18 08:14:19.226 D/MAPINFOPRE: Logging Users
2019-09-18 08:14:19.227 D/USERINFOPRE: ID is userid001 Name is Fred
2019-09-18 08:14:19.227 D/USERINFOPRE: ID is userid002 Name is Mary
2019-09-18 08:14:19.227 D/USERINFOPRE: ID is userid003 Name is Jane
2019-09-18 08:14:19.227 D/USERINFOPRE: ID is userid004 Name is Tom
2019-09-18 08:14:19.227 D/CONVINFO: Logging Conversations
2019-09-18 08:14:19.228 D/CONVINFOPRE: ID is c001 Ttitle is SUBJECT A
2019-09-18 08:14:19.228 D/CONVINFOPRE: ID is c002 Ttitle is SUBJECT X
2019-09-18 08:14:19.233 D/INFOPOST: Logging Conversations via Original Mapping Table
2019-09-18 08:14:19.236 D/INFOPOST: For Conversation SUBJECT AID is (c001) User is Harry ID is (userid001)
2019-09-18 08:14:19.239 D/INFOPOST: For Conversation SUBJECT AID is (c001) User is Jane ID is (userid003)
2019-09-18 08:14:19.241 D/INFOPOST: For Conversation SUBJECT XID is (c002) User is Gertrude ID is (userid002)
2019-09-18 08:14:19.243 D/INFOPOST: For Conversation SUBJECT XID is (c002) User is Tom ID is (userid004)
2019-09-18 08:14:19.243 D/MAPINFOPOST: Logging Users
2019-09-18 08:14:19.244 D/USERINFOPOST: ID is userid001 Name is Harry
2019-09-18 08:14:19.244 D/USERINFOPOST: ID is userid002 Name is Gertrude
2019-09-18 08:14:19.244 D/USERINFOPOST: ID is userid003 Name is Jane
2019-09-18 08:14:19.244 D/USERINFOPOST: ID is userid004 Name is Tom
2019-09-18 08:14:19.244 D/CONVINFO: Logging Conversations
2019-09-18 08:14:19.245 D/CONVINFOPOST: ID is c001 Ttitle is SUBJECT A
2019-09-18 08:14:19.245 D/CONVINFOPOST: ID is c002 Ttitle is SUBJECT X
- 可以看出,外键子项仍然存在,但详细信息已更新,并且没有新的非预期用户。
我有两个 tables - users
和 conversations
。许多 users
可能参加一个 conversation
,一个 user
可能是许多 conversations
@Entity(tableName = "users")
public class User {
@NonNull
@PrimaryKey
@ColumnInfo(name = "userId")
private String id;
...
//Getters and setters
}
@Entity(tableName = "conversations")
public class Conversation {
@NonNull
@PrimaryKey
@ColumnInfo(name = "uuid")
private String id;
...
//Getters and setters
}
追踪哪个user
参与哪个conversation
我用第三个table:
@Entity(tableName = "user_conversation", indices = {@Index(value = {"userId", "conversationUuid"}, unique = true)},
primaryKeys = {"userId", "conversationUuid"},
foreignKeys = {
@ForeignKey(onDelete = CASCADE, entity = User.class, parentColumns = "userId", childColumns = "userId"),
@ForeignKey(onDelete = CASCADE, entity = Conversation.class, parentColumns = "uuid", childColumns = "conversationUuid")
})
public class JoinUserConversation {
@NonNull
private String userId;
@NonNull
private String conversationUuid;
...
//Getters and setters
}
Dao
个对象:
@Dao
public interface UsersDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(User user);
...
}
@Dao
public interface ConversationsDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
long insert(Conversation conversation);
....
}
当我从他们的 table 中 delete
一个 user
或 conversation
时,我也需要从 user_conversation
中删除它们,我使用 onDelete = CASCADE
用于此目的。但是当我insert
一个user
或conversation
到他们table的时候我不需要删除 他们来自 user_conversation
。但据我了解,如果插入实体已经存在于 table 和相应的 user
或 [=18= 中,则 insert
和 @Insert(onConflict = OnConflictStrategy.REPLACE)
将通过 delete
执行] 将从 user_conversation
table 中删除。 如何防止 user_conversation
在 insert
上发生变化?
我相信您可以通过检查要插入的行的 ID 来完成您想要的操作,如果存在则更新,如果不存在则插入。
- 请注意,我尝试将
deferred = true
与@Transaction
一起使用,但由于 CASCADE 执行了它应该执行的操作,所以没有冲突。
例如,对于用户:-
添加
@Query("SELECT count() FROM users WHERE userId = :userId")
int getUserCount(String userId);
和
@Update()
int updateUser(User user);
然后有个方法,比如:-
private void upsertUser(User u) {
if (mWTDao.getUserCount(u.getId()) > 0) {
mWTDao.updateUser(u);
} else {
mWTDao.insert(u);
}
}
- mWTDao 是所有 Dao 存在的地方(示例相同)
例子
考虑以下摘录(来自测试代码):-
......... other code
upsertUser(new User("userid001","Fred"));
upsertUser(new User("userid002","Mary"));
upsertUser(new User("userid003","Jane"));
upsertUser(new User("userid004","Tom"));
mWTDao.insert( new Conversation("c001","SUBJECT A"));
mWTDao.insert( new Conversation("c002","SUBJECT X"));
mWTDao.insert(new JoinUserConversation("userid001","c001"));
mWTDao.insert(new JoinUserConversation("userid003","c001"));
mWTDao.insert(new JoinUserConversation("userid002","c002"));
mWTDao.insert(new JoinUserConversation("userid004","c002"));
logAllInfo("PRE");
upsertUser(new User("userid001","Harry"));
upsertUser(new User("userid002","Gertrude"));
logAllInfo("POST");
}
private void upsertUser(User u) {
if (mWTDao.getUserCount(u.getId()) > 0) {
mWTDao.updateUser(u);
} else {
mWTDao.insert(u);
}
}
private void logAllInfo(String tag) {
Log.d("INFO" + tag,"Logging Conversations via Original Mapping Table ");
for (JoinUserConversation juc: mWTDao.getAllJUC()) {
Conversation c = mWTDao.getConversation(juc.getConversationUuid());
User u = mWTDao.getUser(juc.getUserId());
Log.d("INFO" + tag,"\tFor Conversation " + c.getTitle() + "ID is (" + c.getId() + ") User is " + u.getName() + " ID is (" + u.getId() + ")");
}
Log.d("MAPINFO" + tag,"Logging Users ");
for (User u: mWTDao.getAllUsers()) {
Log.d("USERINFO" + tag,"\tID is " + u.getId() + " Name is " + u.getName());
}
Log.d("CONVINFO","Logging Conversations");
for (Conversation c: mWTDao.getAllConversations()) {
Log.d("CONVINFO" + tag,"\tID is " + c.getId() + " Ttitle is " + c.getTitle());
}
}
- 这会添加 4 个用户(使用 upsertUser 方法)和 2 个对话以及一些 user_conversations
- 显示信息
- 然后尝试使用 upsertUser 方法添加现有用户
- 再次显示信息,显示现有用户已更新。
结果
2019-09-18 08:14:19.214 D/INFOPRE: Logging Conversations via Original Mapping Table
2019-09-18 08:14:19.220 D/INFOPRE: For Conversation SUBJECT AID is (c001) User is Fred ID is (userid001)
2019-09-18 08:14:19.222 D/INFOPRE: For Conversation SUBJECT AID is (c001) User is Jane ID is (userid003)
2019-09-18 08:14:19.224 D/INFOPRE: For Conversation SUBJECT XID is (c002) User is Mary ID is (userid002)
2019-09-18 08:14:19.226 D/INFOPRE: For Conversation SUBJECT XID is (c002) User is Tom ID is (userid004)
2019-09-18 08:14:19.226 D/MAPINFOPRE: Logging Users
2019-09-18 08:14:19.227 D/USERINFOPRE: ID is userid001 Name is Fred
2019-09-18 08:14:19.227 D/USERINFOPRE: ID is userid002 Name is Mary
2019-09-18 08:14:19.227 D/USERINFOPRE: ID is userid003 Name is Jane
2019-09-18 08:14:19.227 D/USERINFOPRE: ID is userid004 Name is Tom
2019-09-18 08:14:19.227 D/CONVINFO: Logging Conversations
2019-09-18 08:14:19.228 D/CONVINFOPRE: ID is c001 Ttitle is SUBJECT A
2019-09-18 08:14:19.228 D/CONVINFOPRE: ID is c002 Ttitle is SUBJECT X
2019-09-18 08:14:19.233 D/INFOPOST: Logging Conversations via Original Mapping Table
2019-09-18 08:14:19.236 D/INFOPOST: For Conversation SUBJECT AID is (c001) User is Harry ID is (userid001)
2019-09-18 08:14:19.239 D/INFOPOST: For Conversation SUBJECT AID is (c001) User is Jane ID is (userid003)
2019-09-18 08:14:19.241 D/INFOPOST: For Conversation SUBJECT XID is (c002) User is Gertrude ID is (userid002)
2019-09-18 08:14:19.243 D/INFOPOST: For Conversation SUBJECT XID is (c002) User is Tom ID is (userid004)
2019-09-18 08:14:19.243 D/MAPINFOPOST: Logging Users
2019-09-18 08:14:19.244 D/USERINFOPOST: ID is userid001 Name is Harry
2019-09-18 08:14:19.244 D/USERINFOPOST: ID is userid002 Name is Gertrude
2019-09-18 08:14:19.244 D/USERINFOPOST: ID is userid003 Name is Jane
2019-09-18 08:14:19.244 D/USERINFOPOST: ID is userid004 Name is Tom
2019-09-18 08:14:19.244 D/CONVINFO: Logging Conversations
2019-09-18 08:14:19.245 D/CONVINFOPOST: ID is c001 Ttitle is SUBJECT A
2019-09-18 08:14:19.245 D/CONVINFOPOST: ID is c002 Ttitle is SUBJECT X
- 可以看出,外键子项仍然存在,但详细信息已更新,并且没有新的非预期用户。