Android 房间更新查询卡在自动生成的代码上
Android Room update query getting stuck on auto generated code
在使用 Android Room 几周并掌握了基本查询之后,我 运行 遇到了尝试更新自定义对象列表的问题。出于某种原因,当 Room 尝试创建 SQLLite 字符串以插入我的新数据时,它会卡在占位符中:
从调试 window:
Caused by: android.database.sqlite.SQLiteException: near "?": syntax error (code 1): , while compiling: UPDATE player_characters SET ability_scores = ?,?,?,?,?,? WHERE playerCharacterID = ?
#################################################################
Error Code : 1 (SQLITE_ERROR)
Caused By : SQL(query) error or missing database.
(near "?": syntax error (code 1): , while compiling: UPDATE player_characters SET ability_scores = ?,?,?,?,?,? WHERE playerCharacterID = ?)
#################################################################
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1005)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:570)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.(SQLiteProgram.java:59)
at android.database.sqlite.SQLiteStatement.(SQLiteStatement.java:31)
at android.database.sqlite.SQLiteDatabase.compileStatement(SQLiteDatabase.java:1375)
at android.arch.persistence.db.framework.FrameworkSQLiteDatabase.compileStatement(FrameworkSQLiteDatabase.java:62)
at android.arch.persistence.room.RoomDatabase.compileStatement(RoomDatabase.java:204)
at com.pathfinderstattracker.pathfindercharactersheet.database.database_daos.PlayerCharacterDao_Impl.updatePlayerCharacterAbilityScores(PlayerCharacterDao_Impl.java:321)
包含查询的 DAO:
@Dao
@TypeConverters({UUIDConverter.class,
AbilityScoreConcreteConverter.class})
public interface PlayerCharacterDao
{
@Query("UPDATE player_characters "+
"SET ability_scores = :playerCharacterAbilityScores "+
"WHERE playerCharacterID = :characterIDToUpdate")
void updatePlayerCharacterAbilityScores(UUID characterIDToUpdate, List<AbilityScore> playerCharacterAbilityScores);
}
以及调用它的存储库命令:
private static class updatePlayerCharacterAbilityScoresAsyncTask extends AsyncTask<Object, Void, Void>
{
private PlayerCharacterDao asyncPlayerCharacterDao;
updatePlayerCharacterAbilityScoresAsyncTask(PlayerCharacterDao dao) {asyncPlayerCharacterDao = dao;}
@Override
protected Void doInBackground(final Object... params)
{
UUID playerCharacterID = (UUID)params[0];
List<AbilityScore> updatedAbilityScores = (ArrayList<AbilityScore>)params[1];
asyncPlayerCharacterDao.updatePlayerCharacterAbilityScores(playerCharacterID, updatedAbilityScores);
return null;
}
}
我可以确认数据正在正确地到达房间查询,我已经尝试将具体对象和接口对象传递到查询中,并且有一个用于单个 AbilityScore 对象和 AbilityScore 列表的转换器对象。任何帮助将不胜感激!
编辑:一些人请求了正在更新的实体:
@Entity(tableName = "player_characters")
@TypeConverters({AlignmentEnumConverter.class,
HitPointsConverter.class,
DamageReductionConverter.class,
StringListConverter.class,
UUIDConverter.class,
StringListConverter.class,
AbilityScoreListConverter.class,
CombatManeuverConverter.class})
public class PlayerCharacterEntity
{
@PrimaryKey
@NonNull
private UUID playerCharacterID;
@ColumnInfo(name="character_name")
private String playerCharacterName;
@ColumnInfo(name="character_level")
private int characterLevel;
@ColumnInfo(name="concentration_check")
private int concentrationCheck;
@ColumnInfo(name="character_alignment")
private AlignmentEnum characterAlignment;
@ColumnInfo(name="total_base_attack_bonus")
private int totalBaseAttackBonus;
@ColumnInfo(name="total_hit_points")
private IHitPoints totalHitPoints;
@ColumnInfo(name="total_ac")
private int totalAC;
@ColumnInfo(name="damage_reduction")
private IDamageReduction damageReduction;
@ColumnInfo(name="languages_known")
private List<String> languagesKnown;
@ColumnInfo(name="ability_scores")
private List<IAbilityScore> abilityScores;
@ColumnInfo(name="combat_Maneuver_stats")
private ICombatManeuver combatManeuverStats;
@ColumnInfo(name="spell_resistance")
private int spellResistance;
@ColumnInfo(name="initiative")
private int initiative;
@ColumnInfo(name="fortitude_save")
private int fortitudeSave;
@ColumnInfo(name="reflex_save")
private int reflexSave;
@ColumnInfo(name="will_save")
private int willSave;
~Getters/Setters and Constructors removed for brevity~
}
编辑: 为了更好的衡量,我想我会为 AbilityScore 包含 @TypeConverter(我已经将其恢复为使用接口而不是具体的早期形式,因为那在代码的其他地方工作,差异似乎没有改变任何东西):
public class AbilityScoreConverter
{
@TypeConverter
public IAbilityScore fromString(String value)
{
IAbilityScore formattedAbilityScore = new AbilityScore();
String[] tokens = value.split(" ");
formattedAbilityScore.setAmount(Integer.parseInt(tokens[0]));
switch(tokens[1])
{
case "STR":
formattedAbilityScore.setStat(AbilityScoreEnum.STR);
case "DEX":
formattedAbilityScore.setStat(AbilityScoreEnum.DEX);
case "CON":
formattedAbilityScore.setStat(AbilityScoreEnum.CON);
case "INT":
formattedAbilityScore.setStat(AbilityScoreEnum.INT);
case "WIS":
formattedAbilityScore.setStat(AbilityScoreEnum.WIS);
case "CHA":
formattedAbilityScore.setStat(AbilityScoreEnum.CHA);
default:
//This may cause issues down the line if a non existent enum gets in the db somehow, but we don't have any error handling yet
//Todo: Add error handling
formattedAbilityScore.setStat(AbilityScoreEnum.STR);
}
return formattedAbilityScore;
}
@TypeConverter
public String toString(IAbilityScore value)
{
return value.toString();
}
}
编辑: 我已经清理了 logcat 文本,只关注 Room/SQLLite 问题。
经过一番搜索,不幸的是,我被迫放弃使用@Query 命令更新我的数据库,而不得不转而使用 Rooms 默认的 @Update 表示法。虽然这确实有效并正确更新了数据库中的数据,但它不允许我只更新某些字段。
在 UPDATE 查询中使用 ArrayList 而不是 List 对我有用。
我关注了。
Impl 构建的差异:
可变列表:
@Override
public void test(int tkID, List<Boolean> test) {
StringBuilder _stringBuilder = StringUtil.newStringBuilder();
_stringBuilder.append("UPDATE TasksTable SET test = ");
final int _inputSize = test.size();
StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
_stringBuilder.append(" WHERE taskID = ");
_stringBuilder.append("?");
final String _sql = _stringBuilder.toString();
SupportSQLiteStatement _stmt = __db.compileStatement(_sql);
数组列表:
@Override
public void test(int tkID, ArrayList<Boolean> test) {
final SupportSQLiteStatement _stmt = __preparedStmtOfTest.acquire();
__db.beginTransaction();
try {
int _argIndex = 1;
final String _tmp;
_tmp = Converters.listBooleanToString(test);
if (_tmp == null) {
_stmt.bindNull(_argIndex);
} else {
_stmt.bindString(_argIndex, _tmp);
}
_argIndex = 2;
_stmt.bindLong(_argIndex, tkID);
_stmt.executeUpdateDelete();
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
__preparedStmtOfTest.release(_stmt);
}
}
如您所见,ArrayList 使用了转换器,而 MutableList 没有。
在使用 Android Room 几周并掌握了基本查询之后,我 运行 遇到了尝试更新自定义对象列表的问题。出于某种原因,当 Room 尝试创建 SQLLite 字符串以插入我的新数据时,它会卡在占位符中: 从调试 window:
Caused by: android.database.sqlite.SQLiteException: near "?": syntax error (code 1): , while compiling: UPDATE player_characters SET ability_scores = ?,?,?,?,?,? WHERE playerCharacterID = ? ################################################################# Error Code : 1 (SQLITE_ERROR) Caused By : SQL(query) error or missing database. (near "?": syntax error (code 1): , while compiling: UPDATE player_characters SET ability_scores = ?,?,?,?,?,? WHERE playerCharacterID = ?) ################################################################# at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method) at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1005) at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:570) at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588) at android.database.sqlite.SQLiteProgram.(SQLiteProgram.java:59) at android.database.sqlite.SQLiteStatement.(SQLiteStatement.java:31) at android.database.sqlite.SQLiteDatabase.compileStatement(SQLiteDatabase.java:1375) at android.arch.persistence.db.framework.FrameworkSQLiteDatabase.compileStatement(FrameworkSQLiteDatabase.java:62) at android.arch.persistence.room.RoomDatabase.compileStatement(RoomDatabase.java:204) at com.pathfinderstattracker.pathfindercharactersheet.database.database_daos.PlayerCharacterDao_Impl.updatePlayerCharacterAbilityScores(PlayerCharacterDao_Impl.java:321)
包含查询的 DAO:
@Dao
@TypeConverters({UUIDConverter.class,
AbilityScoreConcreteConverter.class})
public interface PlayerCharacterDao
{
@Query("UPDATE player_characters "+
"SET ability_scores = :playerCharacterAbilityScores "+
"WHERE playerCharacterID = :characterIDToUpdate")
void updatePlayerCharacterAbilityScores(UUID characterIDToUpdate, List<AbilityScore> playerCharacterAbilityScores);
}
以及调用它的存储库命令:
private static class updatePlayerCharacterAbilityScoresAsyncTask extends AsyncTask<Object, Void, Void>
{
private PlayerCharacterDao asyncPlayerCharacterDao;
updatePlayerCharacterAbilityScoresAsyncTask(PlayerCharacterDao dao) {asyncPlayerCharacterDao = dao;}
@Override
protected Void doInBackground(final Object... params)
{
UUID playerCharacterID = (UUID)params[0];
List<AbilityScore> updatedAbilityScores = (ArrayList<AbilityScore>)params[1];
asyncPlayerCharacterDao.updatePlayerCharacterAbilityScores(playerCharacterID, updatedAbilityScores);
return null;
}
}
我可以确认数据正在正确地到达房间查询,我已经尝试将具体对象和接口对象传递到查询中,并且有一个用于单个 AbilityScore 对象和 AbilityScore 列表的转换器对象。任何帮助将不胜感激!
编辑:一些人请求了正在更新的实体:
@Entity(tableName = "player_characters")
@TypeConverters({AlignmentEnumConverter.class,
HitPointsConverter.class,
DamageReductionConverter.class,
StringListConverter.class,
UUIDConverter.class,
StringListConverter.class,
AbilityScoreListConverter.class,
CombatManeuverConverter.class})
public class PlayerCharacterEntity
{
@PrimaryKey
@NonNull
private UUID playerCharacterID;
@ColumnInfo(name="character_name")
private String playerCharacterName;
@ColumnInfo(name="character_level")
private int characterLevel;
@ColumnInfo(name="concentration_check")
private int concentrationCheck;
@ColumnInfo(name="character_alignment")
private AlignmentEnum characterAlignment;
@ColumnInfo(name="total_base_attack_bonus")
private int totalBaseAttackBonus;
@ColumnInfo(name="total_hit_points")
private IHitPoints totalHitPoints;
@ColumnInfo(name="total_ac")
private int totalAC;
@ColumnInfo(name="damage_reduction")
private IDamageReduction damageReduction;
@ColumnInfo(name="languages_known")
private List<String> languagesKnown;
@ColumnInfo(name="ability_scores")
private List<IAbilityScore> abilityScores;
@ColumnInfo(name="combat_Maneuver_stats")
private ICombatManeuver combatManeuverStats;
@ColumnInfo(name="spell_resistance")
private int spellResistance;
@ColumnInfo(name="initiative")
private int initiative;
@ColumnInfo(name="fortitude_save")
private int fortitudeSave;
@ColumnInfo(name="reflex_save")
private int reflexSave;
@ColumnInfo(name="will_save")
private int willSave;
~Getters/Setters and Constructors removed for brevity~
}
编辑: 为了更好的衡量,我想我会为 AbilityScore 包含 @TypeConverter(我已经将其恢复为使用接口而不是具体的早期形式,因为那在代码的其他地方工作,差异似乎没有改变任何东西):
public class AbilityScoreConverter
{
@TypeConverter
public IAbilityScore fromString(String value)
{
IAbilityScore formattedAbilityScore = new AbilityScore();
String[] tokens = value.split(" ");
formattedAbilityScore.setAmount(Integer.parseInt(tokens[0]));
switch(tokens[1])
{
case "STR":
formattedAbilityScore.setStat(AbilityScoreEnum.STR);
case "DEX":
formattedAbilityScore.setStat(AbilityScoreEnum.DEX);
case "CON":
formattedAbilityScore.setStat(AbilityScoreEnum.CON);
case "INT":
formattedAbilityScore.setStat(AbilityScoreEnum.INT);
case "WIS":
formattedAbilityScore.setStat(AbilityScoreEnum.WIS);
case "CHA":
formattedAbilityScore.setStat(AbilityScoreEnum.CHA);
default:
//This may cause issues down the line if a non existent enum gets in the db somehow, but we don't have any error handling yet
//Todo: Add error handling
formattedAbilityScore.setStat(AbilityScoreEnum.STR);
}
return formattedAbilityScore;
}
@TypeConverter
public String toString(IAbilityScore value)
{
return value.toString();
}
}
编辑: 我已经清理了 logcat 文本,只关注 Room/SQLLite 问题。
经过一番搜索,不幸的是,我被迫放弃使用@Query 命令更新我的数据库,而不得不转而使用 Rooms 默认的 @Update 表示法。虽然这确实有效并正确更新了数据库中的数据,但它不允许我只更新某些字段。
在 UPDATE 查询中使用 ArrayList 而不是 List 对我有用。
我关注了
Impl 构建的差异:
可变列表:
@Override
public void test(int tkID, List<Boolean> test) {
StringBuilder _stringBuilder = StringUtil.newStringBuilder();
_stringBuilder.append("UPDATE TasksTable SET test = ");
final int _inputSize = test.size();
StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
_stringBuilder.append(" WHERE taskID = ");
_stringBuilder.append("?");
final String _sql = _stringBuilder.toString();
SupportSQLiteStatement _stmt = __db.compileStatement(_sql);
数组列表:
@Override
public void test(int tkID, ArrayList<Boolean> test) {
final SupportSQLiteStatement _stmt = __preparedStmtOfTest.acquire();
__db.beginTransaction();
try {
int _argIndex = 1;
final String _tmp;
_tmp = Converters.listBooleanToString(test);
if (_tmp == null) {
_stmt.bindNull(_argIndex);
} else {
_stmt.bindString(_argIndex, _tmp);
}
_argIndex = 2;
_stmt.bindLong(_argIndex, tkID);
_stmt.executeUpdateDelete();
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
__preparedStmtOfTest.release(_stmt);
}
}
如您所见,ArrayList 使用了转换器,而 MutableList 没有。