android .database.sqlite.SQLiteException: рядом с «?»: Синтаксическая ошибка (код 1): - PullRequest
2 голосов
/ 26 мая 2020

Я использую библиотеку Room (шаблон MVVM), и одна из функций Dao возвращает это сообщение об ошибке:

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

Это код Dao:

@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<String>:

@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 предположительно автоматически генерируется Дао и я не влияем на это ...

Ответы [ 2 ]

2 голосов
/ 27 мая 2020

Еще два обходных пути в дополнение к ответу Боба Снайдера (но они должны быть тщательно протестированы):

  1. Чтобы «имитировать» TypeConverter (из списка в строку) самостоятельно (это непростая вещь , На практике не пробовал!):

В 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); 
}

и вызвать его из репозитория / ViewModel:

db.ParcelDao().updatePossibleDeliveryPersonsList(possibleList, tid);
Чтобы заменить несколько ваших методов updateXXX в DAO одним обновлением (у вас много полей в таблице, может быть, лучше попробовать какой-нибудь универсальный способ обновить любые их комбинации?):
@Update
void update(Parcel parcel);

Добавьте в свой DAO метод поиска посылки по id:

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

И в вашем репозитории / 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 голосов
/ 27 мая 2020

В документации к аннотации Query объясняется функция привязки аргументов Room:

В качестве расширения аргументов привязки SQLite Room поддерживает привязку списка параметров к запросу . Во время выполнения Room создаст правильный запрос, чтобы иметь соответствующее количество аргументов привязки в зависимости от количества элементов в параметре метода.

Эта функция, вероятно, предназначалась для использования в предложении where ( как показано в примере документации), но, похоже, применяется повсюду в операторе запроса.

В вашем случае желаемое поведение состоит в том, чтобы Room применил ваш преобразователь типов, но вместо этого Room игнорирует преобразователь типов и создание специальной привязки списка.

Я думаю, вам придется обойти это ограничение текущей реализации Room. Вы можете написать отчет об ошибке , чтобы получить подтверждение того, что приведенное здесь объяснение верно.

Один вариант для обходного пути , который будет использовать преобразователи типов: для определения этого класса:

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); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...