Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sugar ORM just won't create tables

I am working on a standalone library project that requires persisting a simple model. Here is what my SugarRecord looks like:

/**
 *  Keeping track of previously received messages by ID
 */

public class MessageRequestIdModel extends SugarRecord {

    protected String messageRequestId;

    public MessageRequestIdModel() {

    }

    public MessageRequestIdModel(String messageRequestId) {
        this.messageRequestId = messageRequestId;
    }

    public String getMessageRequestId() {
        return this.messageRequestId;
    }

    public static boolean exists(String id) {
        return MessageRequestIdModel.find(
                MessageRequestIdModel.class,
                "messageRequestId = ?",
                id
        ).size() != 0;
    }
}

In a repository class, I am attempting to persist it by calling this method:

@Override
public void save(MessageRequestId messageRequestId) {
    new MessageRequestIdModel(messageRequestId.getId()).save();
}

I now attempt to test this by using an android.test.InstrumentationTestCase where I pass a Context to Sugar like so:

SugarContext.init(getInstrumentation().getContext());

This results in this error when I run the test: (truncating to keep this question a succinct read)

android.database.sqlite.SQLiteException: no such table: MESSAGE_REQUEST_ID_MODEL (code 1): , while compiling: INSERT or REPLACE...

Troubleshooting I've already attempted:

  • Keeping a different Manifest for the test package to pass the .test package name to SugarORM. No change in behaviour
  • Adding a MessageRequestIdModel.findById(MessageRequestIdModel.class, (long) 1); like in the other SO posts. Changes error to itself (Showing full stack-trace here in case it helps):

    android.database.sqlite.SQLiteException: no such table: MESSAGE_REQUEST_ID_MODEL (code 1): , while compiling: SELECT * FROM MESSAGE_REQUEST_ID_MODEL WHERE id=? LIMIT 1
    
    at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
    at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
    at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:500)
    at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
    at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
    at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
    at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1316)
    at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1163)
    at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1034)
    at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1240)
    at com.orm.SugarRecord.find(SugarRecord.java:192)
    at com.orm.SugarRecord.findById(SugarRecord.java:102)
    at pm.tin.apprise.entities.message_request_ids.MessageRequestIdModelRepository.save(MessageRequestIdModelRepository.java:19)
    
  • I've tried removing all Sugar ORM config from the Manifest like suggested by many - this changes nothing

  • I've tried creating a Sample App module and tried running it as a test-case for that app, in case Standalone apps didn't get the right resources on the emulator/device (I've tested on both)

  • I've tried incrementing the VERSION number for the database

  • I've tried switching to an ActivityTestCase and using getActivity().getApplicationContext(). This essentially fails with an error that suggests that this Context is incomplete to be able to setup SQLite

As you can see, I have pushed hard at this boulder all night long, but at this point it is seeming Sisyphean and I have absolutely no lead for my next debug attempt other than to use a different ORM than Sugar (which doesn't really seem to be the problem). There is nothing more emasculating that not being able to run SQLite in a Test Case and I cry to the Holy Programmer Consciousness in you for help :-'(

like image 258
Angad Avatar asked Mar 03 '16 07:03

Angad


3 Answers

This issue has been observed in Android Studio 2.x.x-beta versions (most notably 2.0.0-beta6) and has its root cause in the 'Instant Run' feature.

I imagine this may be fixed shortly, but for this to work in the meantime, you should disable the feature in the following menu

File | Settings | Build, Execution, Deployment | Instant Run

Cleaning and then building the application should resolve these issues.

You can see the related Sugar bug report here.

like image 101
Ed George Avatar answered Nov 01 '22 23:11

Ed George


This should conclusively solve this problem for all the folks out there struggling to get Sugar ORM to work out of the box - use the SQL versioning system to manually fire creation SQL.

In the above use-case, here is how you do it:

1.) Change Sugar ORM config's DB version to a new number (say N) such that it is greater than the current version OR change database name

2.) Create a file ModuleName/src/main/assets/sugar_upgrades/<N>.sql with your SQL; showing mine, in case it helps:

DROP TABLE MESSAGE_REQUEST_ID_MODEL;

CREATE TABLE MESSAGE_REQUEST_ID_MODEL(ID INTEGER PRIMARY KEY AUTOINCREMENT, MESSAGE_REQUEST_ID CHAR(128));

This will force Sugar to fire your SQL to create the table for you (albeit manually).

Additional Notes

  • This section of the Sugar ORM manual is the inspiration behind this (albeit hacky) fix: http://satyan.github.io/sugar/migration.html
  • I have commented out the package name from Sugar config
  • Sugar works with an Instrumentation Application Context. In a base class of InstrumentationTestCase, simply do SugarContext.init(getInstrumentation().getTargetContext()) as shown in the original question
like image 28
Angad Avatar answered Nov 02 '22 00:11

Angad


your problem may be creation of class...

public class MessageRequestIdModel extends SugarRecord<MessageRequestIdModel> {

    protected String messageRequestId;

    public MessageRequestIdModel() {

    }

    public MessageRequestIdModel(String messageRequestId) {
        this.messageRequestId = messageRequestId;
    }

    public String getMessageRequestId() {
        return this.messageRequestId;
    }

    public static boolean exists(String id) {
        return MessageRequestIdModel.find(
                MessageRequestIdModel.class,
                "messageRequestId = ?",
                id
        ).size() != 0;
    }
}

please recheck with my code.

like image 1
rockstar Avatar answered Nov 01 '22 23:11

rockstar