2014-05-18 75 views
0

嘿傢伙我一直在這個問題上困住了很長一段時間,但我似乎無法解決它。Android SQLite查詢與哪裏不工作

我嘗試從我的Android應用程序中的SQLite數據庫查詢一行,我有一些奇怪的行爲。

我有以下的單元測試:

public class DatabaseTest extends AndroidTestCase { 
    ... 
    public void testSaveMeeting() { 
     Meeting meeting = new Meeting(1, MeetingStatus.ONGOING); 
     MeetingDataSource mds = new MeetingDataSource(getContext()); 

     long meetingId = mds.save(meeting); 
     assertEquals(meeting, mds.getById(meetingId)); 
    } 
} 

在這裏,我嘗試我的模型對象meeting保存到數據庫中與我的數據庫映射。下面的代碼片段是我的模型Meeting存儲應保存到數據庫中的數據:

public class Meeting { 
    private long id; 
    private MeetingStatus meetingStatus; 

    public Meeting() {} 

    public Meeting(long meetingId, MeetingStatus meetingStatus) { 
     this.id = meetingId; 
     this.meetingStatus = meetingStatus; 
    } 

    public long getId() { return id; } 
    public void setId(long id) { this.id = id; } 

    public void setMeetingStatus(MeetingStatus meetingStatus) { this.meetingStatus = meetingStatus; } 
    public MeetingStatus getMeetingStatus() { return meetingStatus; } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 

     Meeting meeting = (Meeting) o; 

     return id == meeting.id && meetingStatus == meeting.meetingStatus; 
    } 

    @Override 
    public int hashCode() {...} 
} 

而且我MeetingDataSource是一個映射器類,我試圖映射我的模型對象到數據庫中,反之亦然。該類如下所示:

public class MeetingDataSource extends DataSource<Meeting> { 
    private static String REQUEST_TABLE_NAME = DatabaseContract.MeetingTable.TABLE_NAME; 

    private static String[] ALL_COLUMNS = { 
      DatabaseContract.MeetingTable._ID, 
      DatabaseContract.MeetingTable.COLUMN_NAME_STATUS 
    }; 

    public MeetingDataSource(Context context) { super(context); } 

    @Override 
    public Meeting cursorToObject(Cursor cursor) { 
     if(cursor != null && cursor.moveToFirst()) { 
      Meeting meeting = new Meeting(); 
      meeting.setId(cursor.getLong(0)); 
      meeting.setMeetingStatus(MeetingStatus.valueOfLabel(cursor.getString(1))); 

      return meeting; 
     } 
     return null; 
    } 

@Override 
    protected ContentValues objectToContentValues(Meeting meeting) { 
     ContentValues values = new ContentValues(); 
     values.put(DatabaseContract.MeetingTable._ID, meeting.getId()); 
     values.put(DatabaseContract.MeetingTable.COLUMN_NAME_STATUS, meeting.getMeetingStatus().getLabel()); 
     return values; 
    } 

    @Override 
    public Meeting getById(long id) { 
     try { 
      openReadConnection(); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 

     String where = DatabaseContract.MeetingTable._ID + " = ?"; 
     String[] whereValues = { String.valueOf(id) }; 

     // I think this is the part where my Problem is. 
     Cursor cursor = database.query(
       REQUEST_TABLE_NAME, 
       ALL_COLUMNS, 
       where, 
       whereValues, 
       null, 
       null, 
       null); 

     Meeting meeting = cursorToObject(cursor); 

     closeConnection(); 
     return meeting; 
    } 

    @Override 
    public long save(Meeting meeting) { 
     try { 
      openWriteConnection(); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 

     long rowId = database.insert(REQUEST_TABLE_NAME, null, objectToContentValues(meeting)); 

     closeConnection(); 
     return rowId; 
    } 

    @Override 
    public void update(Meeting meeting) {...} 

    @Override 
    public List<Meeting> getAll() {...} 
} 

此類擴展以下適配器DataSource。這是SQLiteOpenHelper一個包裝物,用於創建數據庫本身:

public abstract class DataSource<DatabaseTableType> { 
    protected Context context; 
    protected SQLiteDatabase database; 
    private DatabaseHelper dbHelper; 

    public DataSource(Context context) { 
     this.context = context; 
     dbHelper = new DatabaseHelper(context); 
    } 

    protected void openReadConnection() throws SQLException { 
     database = dbHelper.getReadableDatabase(); 
    } 
    protected void openWriteConnection() throws SQLException { database = dbHelper.getWritableDatabase(); } 
    protected void closeConnection() { 
     dbHelper.close(); 
    } 

    protected abstract DatabaseTableType cursorToObject(Cursor cursor); 
    protected abstract ContentValues objectToContentValues(DatabaseTableType object); 

    public abstract DatabaseTableType getById(long id); 
    public abstract List<DatabaseTableType> getAll(); 

    public abstract long save(DatabaseTableType object); 
    public abstract void update(DatabaseTableType object); 
} 

現在這裏是奇數部分: 當我加入其中的方法getById像上面我的assertEquals聲明和論點在我MeetingDataSource在測試中失敗了,因爲我的光標是空的,所以的cursorToObject 返回值,但如果我離開它,就像這樣:

Cursor cursor = database.query(
    REQUEST_TABLE_NAME, 
    ALL_COLUMNS, 
    null, 
    null, 
    null, 
    null, 
    null); 

我的測試suceeds,這使我相信,正確的對象已經產生通過cursorToObject。 我也試過rawQuery

Cursor cursor = database.rawQuery("SELECT * FROM " + REQUEST_TABLE_NAME + " WHERE _id = ?", whereValues); 

返回也null。而

Cursor cursor = database.rawQuery("SELECT * FROM " + REQUEST_TABLE_NAME, null); 

返回正確的Meeting並且還讓我的測試通過。

我非常感謝任何答案:)

編輯1

這migth是有幫助的,看我如何定義我的表,什麼我SQLiteOpenHelper一樣。

這裏是我的DatabaseHelper延伸SQLiteOpenHelper創造和推倒我的數據庫時,它的首次訪問的:

public class DatabaseHelper extends SQLiteOpenHelper { 
    private static final String TAG = "DatabaseHelper"; 
    public static final int DATABASE_VERSION = 1; 
    public static final String DATABASE_NAME = "lma.db"; 

    public DatabaseHelper(Context context) { 
     super(context, DATABASE_NAME, null, DATABASE_VERSION); 
    } 

    @Override 
    public void onCreate(SQLiteDatabase db) { 
     db.execSQL(DatabaseContract.AttendanceStatusTable.SETUP_TABLE); 
     db.execSQL(DatabaseContract.MeetingStatusTable.SETUP_TABLE); 

     db.execSQL(DatabaseContract.MeetingTable.CREATE_TABLE); 
     db.execSQL(DatabaseContract.AttendanceTable.CREATE_TABLE); 
     db.execSQL(DatabaseContract.LocationTable.CREATE_TABLE); 
     db.execSQL(DatabaseContract.ContactPositionTable.CREATE_TABLE); 
     db.execSQL(DatabaseContract.RouteTable.CREATE_TABLE); 
     db.execSQL(DatabaseContract.StepTable.CREATE_TABLE); 
     db.execSQL(DatabaseContract.WarningTable.CREATE_TABLE); 
     db.execSQL(DatabaseContract.RoutesToWarningsTable.CREATE_TABLE); 
     db.execSQL(DatabaseContract.RoutesToStepsTable.CREATE_TABLE); 

     Log.i(TAG, "Database created"); 
    } 

    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     db.execSQL(DatabaseContract.RoutesToStepsTable.DROP_TABLE); 
     db.execSQL(DatabaseContract.RoutesToWarningsTable.DROP_TABLE); 
     db.execSQL(DatabaseContract.WarningTable.DROP_TABLE); 
     db.execSQL(DatabaseContract.StepTable.DROP_TABLE); 
     db.execSQL(DatabaseContract.RouteTable.DROP_TABLE); 
     db.execSQL(DatabaseContract.ContactPositionTable.DROP_TABLE); 
     db.execSQL(DatabaseContract.LocationTable.DROP_TABLE); 
     db.execSQL(DatabaseContract.AttendanceTable.DROP_TABLE); 
     db.execSQL(DatabaseContract.MeetingTable.DROP_TABLE); 

     db.execSQL(DatabaseContract.MeetingStatusTable.DROP_TABLE); 
     db.execSQL(DatabaseContract.AttendanceStatusTable.DROP_TABLE); 

     Log.i(TAG, "Database dropped"); 

     onCreate(db); 
    } 
} 

在我DatabaseContract我定義所有的SQL語句來創建我的表。它還定義了我的列名和表名:

public final class DatabaseContract { 
    private static final String INT_TYPE = " INTEGER"; 
    private static final String VARCHAR_TYPE = " VARCHAR(25)"; 

    private static final String COMMA = ", "; 

    private static final String DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS "; 
    private static final String PRIMARY_KEY = " PRIMARY KEY"; 
    private static final String NOT_NULL = " NOT NULL"; 

    // To prevent someone from accidentally instantiating the contract class 
    public DatabaseContract() {} 

    // Enum Types 
    ... 
    public static abstract class MeetingStatusTable implements BaseColumns { 
     public static final String TABLE_NAME = "meeting_statuses"; 
     public static final String COLUMN_NAME_TYPE = "type"; 

     public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + COLUMN_NAME_TYPE + VARCHAR_TYPE + PRIMARY_KEY + ");"; 
     public static final String INSERT_DATA = "INSERT INTO " + TABLE_NAME + "(" + COLUMN_NAME_TYPE + ") " + "VALUES (\"NEW\"), (\"ONGOING\"), (\"TERMINATED\"), (\"COMPLETED\");"; 

     public static final String SETUP_TABLE = CREATE_TABLE + INSERT_DATA; 
     public static final String DROP_TABLE = DROP_TABLE_STATEMENT + TABLE_NAME + ";"; 
    } 

    // Data Tables 
    public static abstract class MeetingTable implements BaseColumns { 
     public static final String TABLE_NAME = "meetings"; 
     public static final String COLUMN_NAME_STATUS = "status"; 

     public static final String CREATE_TABLE = 
       "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + 
       _ID + INT_TYPE + PRIMARY_KEY + NOT_NULL + COMMA + 
       COLUMN_NAME_STATUS + VARCHAR_TYPE + NOT_NULL + COMMA + 
       " FOREIGN KEY (" + COLUMN_NAME_STATUS + ") REFERENCES " + MeetingStatusTable.TABLE_NAME + " (" + MeetingStatusTable.COLUMN_NAME_TYPE + ")" + 
       ");"; 

     public static final String DROP_TABLE = DROP_TABLE_STATEMENT + TABLE_NAME + ";"; 
    } 
    ... 
} 

EDIT 2

那麼在評論中我得到了我的要求,我MeetingDataSourcesave方法實際上是否返回正確的值,這是不案件。通過編輯,我在我的MeetingDataSource中添加了我的保存方法的代碼,這似乎是一個實際的麻煩製造者。

+0

表的定義? 'save'返回的實際值是多少? –

+0

@CL。我編輯我的郵政表格定義。那麼這是一個很好的問題,實際上我會檢查一個額外的斷言。 – TehQuila

+0

@CL。似乎有問題:當我在我的代碼中有以下斷言:assertEquals(meeting.getId(),meetingId);我得到:'AssertionFailedError:expected:<1>但是:<-1>'我也會發布我的save方法的代碼。 – TehQuila

回答

0

因此,感謝下面我的問題的評論,我能夠弄清楚發生了什麼問題。因爲我測試我的DATABSE映射器我在我的建立呼叫的

mockContext.deleteDatabase(DatabaseHelper.DATABASE_NAME); 

()方法對我的測試,以確保之前我的測試中我的數據庫是空的。但是當我意識到setUp()在每次測試之前執行時,我都刪除了這一行。由於在每次測試運行後我都沒有重新安裝我的應用程序,因此數據庫未被清理,因此插入嘗試插入已存在於數據庫中的數據,因此返回-1作爲索引,因爲表中的主鍵必須是唯一的。