【问题标题】:android.database.sqlite.SQLiteException: near "?": syntax error (code 1):android.database.sqlite.SQLiteException:靠近“?”:语法错误(代码1):
【发布时间】:2020-09-13 18:27:06
【问题描述】:

我正在使用 Room 库(MVVM 模式),其中一个 Dao 函数返回此错误消息:

android.database.sqlite.SQLiteException: near "?": syntax error (code 1): , while compiling: UPDATE parcel_table SET possibleDeliveryPersonsList = ?,? WHERE id = ?

这是道代码:

@Dao
public interface ParcelDao {
    @Insert
    void insert(Parcel parcel);

    @Delete
    void delete(Parcel parcel);

    @Query("UPDATE parcel_table SET shippingDate=:shippingDate WHERE id = :id")
    void updateShippingDate(String shippingDate, int id);

    @Query("UPDATE parcel_table SET parcelStatus=:status WHERE id = :id")
    void updatePackageStatus(Enums.ParcelStatus status, int id);

    @Query("UPDATE parcel_table SET deliveryPersonName=:deliveryPersonName WHERE id = :id")
    void updateDeliveryPersonName(String deliveryPersonName, int id);

    @Query("UPDATE parcel_table SET possibleDeliveryPersonsList = :possibleList WHERE id = :tid")
    void updatePossibleDeliveryPersonsList(List<String> possibleList, int tid);

    @Query("DELETE FROM parcel_table")
    void deleteAllParcels();

    @Query("SELECT * from parcel_table")
    LiveData<List<Parcel>> getParcels();
}

这是 Parcel 类的一部分:

@Entity(tableName = "parcel_table")
public class Parcel {
    private Enums.ParcelType parcelType;
    private boolean isFragile;
    private Enums.ParcelWeight parcelWeight;
    private LatLng warehouseLocation;
    private String recipientName;
    private LatLng recipientAddress;
    private String recipientEmail;
    private String recipientPhone;
    private String dateReceived;
    private String shippingDate;
    private Enums.ParcelStatus parcelStatus;
    private String deliveryPersonName;
    private String fireBasePushId;
    private List<String> possibleDeliveryPersonsList;
@PrimaryKey(autoGenerate = true)
    @NonNull
    private int id;
        //and more...
}

List&lt;String&gt; 类型转换器:

@TypeConverter
    public String listToString(List<String> list) {
        String joined = TextUtils.join(", ", list);
        return joined;
    }

    @TypeConverter
    public List<String> stringToList(String string) {
        List<String> myList = new ArrayList<String>(Arrays.asList(string.split(",")));
        return myList;
    }

我不知道该怎么做,因为 SQLite 代码据说是由 Dao 自动生成的,我对它没有任何影响......

【问题讨论】:

  • 您是否使用TypeConverter 来处理数据库中List&lt;String&gt; 值的存储?如果是这样,请更新您的帖子以包含它的代码。
  • 今天结束了。我明天再看看这个。我能够重现该错误。 Room 似乎不支持您想要的行为。如果您查看生成的查询代码(在文件ParcelDao_impl.java 中),您会看到“?”的数量是列表参数中的字符串数量。不使用转换器。实现逻辑可能是针对list argument in the WHERE clause 的情况。
  • @BobSnyder 谢谢!如果你明天能帮助我,我会很高兴。

标签: android sqlite android-studio android-sqlite android-room


【解决方案1】:

除了 Bob Snyder 的回答之外还有两个解决方法(但需要彻底测试):

  1. 自己“模仿”TypeConverter(从List到String)(这是一个棘手的事情,我没有在实践中尝试过!):

在 DAO 中,将 possibleList 的类型更改为 String:

@Query("UPDATE parcel_table SET possibleDeliveryPersonsList = :possibleList WHERE id = :tid")
    void updatePossibleDeliveryPersonsList(String possibleList, int tid);

添加转换的辅助方法(也可以放在DAO):

void updatePossibleDeliveryPersonsList(List<String> possibleList, int tid) {
   String listToString = TextUtils.join(", ", possibleList); 
   // copied from your converter, it could be put in some common function to follow DRY
   updatePossibleDeliveryPersonsList(listToString, tid); 
}

并从 Repository/ViewModel 调用它:

db.ParcelDao().updatePossibleDeliveryPersonsList(possibleList, tid);
  1. 用单个更新替换 DAO 中的多个 updateXXX 方法(表中有很多字段,尝试一些通用方法来更新它们的任何组合会更好吗?):
@Update
void update(Parcel parcel);

添加到您的 DAO 方法中以通过 id 搜索包裹:

@Query("SELECT * from parcel_table where id = :id")
Parcel getParcel(int id);

首先在您的 Repository/ViewModel 中获取 Parcel,然后对其进行更改(状态、名称等),然后更新数据库:

Parcel parcel = db.ParcelDao().getParcel(id); // let's say it can't be null
parcel.shippingDate = yourShippingDate; // or change here any of your other fields, including list
db.ParcelDao().update(parcel);

【讨论】:

    【解决方案2】:

    Query 注释的文档解释了 Room 参数绑定的一个特性:

    作为 SQLite 绑定参数的扩展,Room 支持绑定 查询的参数列表。在运行时,Room 将构建 正确的查询具有匹配数量的绑定参数,具体取决于 方法参数中的项目数。

    此功能可能旨在用于 where 子句(如文档示例中所示),但似乎适用于查询语句中的任何地方。

    在您的情况下,所需的行为是让 Room 应用您的类型转换器,但 Room 忽略了类型转换器并生成特殊列表绑定。

    我认为您将不得不解决当前 Room 实现的这个限制。您可能想写一个Room bug-report 来确认这里提供的解释是正确的。

    一个将使用类型转换器的option for workaround 是定义这个类:

    public class DeliveryPersonsUpdate {
        public int id;
        public List<String> deliveryPersons;
    
        public DeliveryPersonsUpdate(int id, List<String> deliveryPersons) {
            this.id = id;
            this.deliveryPersons = deliveryPersons;
        }
    }
    

    然后将此方法添加到您的 Dao 中:

    @Update(entity = Parcel.class)
    void update(DeliveryPersonsUpdate update);
    

    调用示例:

    db.ParcelDao().update(new DeliveryPersonsUpdate(id, personsList); 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-04
      • 2020-11-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多