Search code examples
androidsqliteactiveandroid

Cannot save null column value in ActiveAndroid


To make it simple, I have this model:

@Table(name = "Items")
class TItem extends Model {
    @Column(name = "title")
    private String      mTitle;

    public String getTitle() { return mTitle; }

    public void setTitle(String title) { mTitle = title; }
}

And I'm failing in my testings doing that:

    //Create new object and save it to DDBB
    TItem r = new TItem();
    r.save();

    TItem saved = new Select().from(TItem.class).where("id=?", r.getId()).executeSingle();
    //Value for saved.getTitle() = null  --> OK

    r.setTitle("Hello");
    r.save();
    saved = new Select().from(TItem.class).where("id=?", r.getId()).executeSingle();
    //Value for saved.getTitle() = "Hello"  --> OK

    r.setTitle(null);
    r.save();
    saved = new Select().from(TItem.class).where("id=?", r.getId()).executeSingle();
    //Value for saved.getTitle() = "Hello"  --> FAIL

It seems I cannot change a column value from anything to null in ActiveAndroid. Very strange. Is it a bug? I didn't find anything about it, but looks pretty basic this functionallity.

If I debug the app and follow the saving method, the last command it reaches is in SQLLiteConnection.java:

private void bindArguments(PreparedStatement statement, Object[] bindArgs) {
    ....
    // It seems ok, as it is really inserting a null value in the DDBB
    case Cursor.FIELD_TYPE_NULL:
        nativeBindNull(mConnectionPtr, statementPtr, i + 1);
    ....
}

I cannot see further, as "nativeBindNull" is not available


Solution

  • Finally I found what happened, and the problem is in ActiveAndroid library.

    The null value is saved propertly to DDBB, but is not retrieved correctly. As ActiveAndroid uses cached items, when getting an element, it gets an "old version" and updates it with the new values. Here is where the library fails, because is checking that if not null replace the value, otherwise, nothing.

    To solve this, we'll have to change it from the library, in the class Model.java:

    public final void loadFromCursor(Cursor cursor) {
    
        List<String> columnsOrdered = new ArrayList<String>(Arrays.asList(cursor.getColumnNames()));
        for (Field field : mTableInfo.getFields()) {
            final String fieldName = mTableInfo.getColumnName(field);
            Class<?> fieldType = field.getType();
            final int columnIndex = columnsOrdered.indexOf(fieldName);
            ....
    
            if (columnIsNull) {
                <strike>field = null;</strike> //Don't put the field to null, otherwise we won't be able to change its content
                value = null;
            }
    
            ....
    
            <strike>if (value != null)</strike> {   //Remove this check, to always set the value
                field.set(this, value);
            }
            ....
        }
        ....
    }