web-dev-qa-db-ja.com

Android列 '_id'は存在しませんか?

メモ帳の例で機能するものに問題があります。 NotepadCodeLab/Notepadv1Solutionのコードは次のとおりです。

_String[] from = new String[] { NotesDbAdapter.KEY_TITLE };
int[] to = new int[] { R.id.text1 };

SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
R.layout.notes_row, c, from, to);
_

このコードは正常に動作するようです。しかし、明確にするために、 [〜#〜] adb [〜#〜] ユーティリティを実行し、SQLite 3を実行しました。次のようにスキーマを検査しました。

sqlite> .schema

_CREATE TABLE Android_metadata (locale TEXT);
CREATE TABLE notes (_id integer primary key autoincrement, title text
not null, body text not null);
_

すべてが私には良いようです。


さて、私のアプリケーションを見てみましょう。これは、見る限りでは、いくつかの小さな変更を加えても基本的に同じです。コードを単純化および単純化しましたが、問題は解決しません。

_String[] from = new String[] { "x" };
int[] to = new int[] { R.id.x };

SimpleCursorAdapter adapter = null;
try
{
    adapter = new SimpleCursorAdapter(this, R.layout.circle_row, cursor, from, to);
}
catch (RuntimeException e)
{
    Log.e("Circle", e.toString(), e);
}
_

アプリケーションを実行すると、Log.e()ステートメントからRuntimeExceptionが取得され、LogCatに次の出力が表示されます。

LogCatメッセージ:

Java.lang.IllegalArgumentException:列 '_id'は存在しません

そこで、SQLite 3に戻って、私のスキーマの違いを確認します。

sqlite> .schema CREATE TABLE Android_metadata(ロケールTEXT); CREATE TABLE circles(_id integer primary key autoincrement、sequence integer、radius real、x real、y real);

「_id」が欠落している方法がわかりません。

私は何を間違えましたか?

私のアプリケーションとメモ帳の例との違いの1つは、Eclipseウィザードを使用してアプリケーションを最初から作成することから始めましたが、サンプルアプリケーションは既にまとめられています。新しいアプリケーションでSQLiteデータベースを使用するために、何らかの環境変更が必要ですか?

72
Andrew

CursorAdapterのドキュメント 状態:

カーソルには_idという名前の列が含まれている必要があります。そうでない場合、このクラスは機能しません。

SimpleCursorAdapterは派生クラスであるため、このステートメントが適用されるようです。しかし、この声明は技術的に間違っており、初心者を多少誤解させます。カーソルのresult setには、カーソル自体ではなく_idが含まれている必要があります。
この種の速記文書は彼らにとって明らかであるため、これはDBAにとって明らかであると確信しています。カーソルはイテレータまたはポインタのようなもので、データを移動するためのメカニズムのみが含まれ、列自体は含まれません。

Loaders documentation には、_idprojectionパラメーターに含まれていることがわかる例が含まれています。

static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
    Contacts._ID,
    Contacts.DISPLAY_NAME,
    Contacts.CONTACT_STATUS,
    Contacts.CONTACT_PRESENCE,
    Contacts.PHOTO_ID,
    Contacts.LOOKUP_KEY,
};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    // ...
    return new CursorLoader(getActivity(), baseUri,
            CONTACTS_SUMMARY_PROJECTION, select, null,
            Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
150
user405821

これは 回答済み でした。ここでより包括的にしたいと思います。

SimpleCursorAdapterでは、カーソルの結果セットに正確に「_id」という名前の列が含まれている必要があります。テーブルで「_id」列を定義しなかった場合、スキーマを変更するのを急がないでください。 SQLiteは、すべてのテーブルに「rowid」という非表示列を自動的に追加しました。必要なことは、rowidを明示的に選択し、「_ id」としてエイリアスするだけです。

SQLiteDatabase db = mHelper.getReadableDatabase();      
Cursor cur =  db.rawQuery( "select rowid _id,* from your_table", null);
104
Tim Wu

Tim Wuのコードは本当に機能しています...

Db.queryを使用している場合、次のようになります...

db.query(TABLE_USER, new String[] { 
                "rowid _id",
                FIELD_USERNAME,
                }, 
                FIELD_USERNAME + "=" + name, 
                null, 
                null, 
                null, 
                null);
20
Deepzz

はい、SELECT文字列クエリも変更してこの問題を修正します。

String query = "SELECT t.*,t.id as _id FROM table t "; 
8
Felipe FMMobile

このエラーの問題を解決したのは、DBクエリに_id列を含めなかったことです。それを追加することで問題が解決しました。

7
RoadXY

これはおそらくもう関係ないでしょうが、私は今日同じ問題にぶつかりました。列名では大文字と小文字が区別されます。 _ID列がありましたが、Androidには_id列が必要です。

6
zmbq

Sqliteでドキュメントを読む場合、INTEGER PRIMARY KEY型の列を作成するとROWIDが内部的にエイリアスされるため、すべてのSELECTでエイリアスを追加する手間をかける価値はありません。テーブルを定義する列の列挙。

http://www.sqlite.org/autoinc.html

_IDがROWIDから逸脱する可能性があるAUTOINCREMENTオプションの代わりに、これをROWIDとして使用する方が簡単です。 _IDをROWIDに関連付けることは、主キーがinsert/insertOrThrowから返されることを意味します。 ContentProviderを作成している場合、返されたUriでこのキーを使用できます。

0
Eric Woodruff

テーブルに_id列がないことを処理する別の方法は、必要に応じて_id列を追加するCursorWrapperのサブクラスを記述することです。

これには、テーブルやクエリを変更する必要がないという利点があります。

このようなクラスを作成しました。興味がある場合は、 https://github.com/cmgharris/WithIdCursorWrapper で見つけることができます。

0
cmgharris