2014-05-18 78 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作为索引,因为表中的主键必须是唯一的。