【问题标题】:I have issues when trying to access and set my foreign key in my database尝试在数据库中访问和设置外键时遇到问题
【发布时间】:2025-11-22 05:00:06
【问题描述】:

使用 android studio 运行我的应用时出现以下错误。

错误

===============================================

java.lang.IllegalStateException: 无法从 CursorWindow 读取第 0 行 col -1。确保 Cursor 在从中访问数据之前已正确初始化。

我的数据库是 SQLite。 我的应用程序允许用户注册和登录。 运动应用。

他们可以从这里将“玩家”添加到他们的团队中。 我在我的数据库中设置了两张表,一张用于用户,一张用于玩家,用户表中的“user_id”字段用作链接两个数据库的外键。 基本上只有添加了某个玩家的登录用户才能看到该玩家的信息,而其他用户创建的所有其他信息都看不到。

最初,该应用程序将玩家保存到正确的牌桌。 但是外键没有被填充。 然后我重新编写了代码来纠正这个问题。 然而,这是我遇到这个新问题的时候。

非常感谢任何帮助或建议。

1) DatabaseHelper.java

    public class DatabaseHelper extends SQLiteOpenHelper {

        private static final int DATABASE_VERSION = 1;
        private static final String DATABASE_NAME = "MyDB1.db";
        private static final String TABLE_USER = "User";
        private static final String COLUMN_USER_NAME = "User_name";
        private static final String COLUMN_USER_ID = "User_id";
        private static final String COLUMN_USER_EMAIL = "User_email";
        private static final String COLUMN_USER_PASSWORD = "User_password";

        private static final String TABLE_PLAYERS = "Player";
        private static final String COLUMN_PLAYER_NAME = "Player_name";
        private static final String COLUMN_PLAYER_AGE = "Player_age";
        private static final String COLUMN_PLAYER_WEIGHT = "Player_weight";
        private static final String COLUMN_PLAYER_HEIGHT = "Player_height";
        private static final String COLUMN_PLAYER_ID = "Player_id";
        private static final String FOREIGN_PLAYER_ID = COLUMN_USER_ID;
       // private static final Image COLUMN_PLAYER_IMAGE ;

        // Table 1 : Login/Register
        private String CREATE_USER_TABLE = "CREATE TABLE " + TABLE_USER + "(" + COLUMN_USER_NAME + " TEXT,"
                + COLUMN_USER_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                + COLUMN_USER_EMAIL + " TEXT," + COLUMN_USER_PASSWORD + " TEXT" + ")";


        // Table 2 : Adding players
        private String CREATE_PLAYER_TABLE = "CREATE TABLE " + TABLE_PLAYERS + "(" + COLUMN_PLAYER_NAME + " TEXT,"
                + COLUMN_PLAYER_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                + COLUMN_PLAYER_AGE + " INTEGER," + COLUMN_PLAYER_WEIGHT + " INTEGER," + COLUMN_PLAYER_HEIGHT + " INTEGER, " + FOREIGN_PLAYER_ID + " INTEGER," + "FOREIGN KEY(" + FOREIGN_PLAYER_ID + ") REFERENCES " + TABLE_USER + "(User_id) " + ")";


        // Drop tables

        private String DROP_USER_TABLE = "DROP TABLE IF EXISTS " + TABLE_USER ;
        private String DROP_PLAYER_TABLE = "DROP TABLE IF EXISTS " + TABLE_PLAYERS ;


        public DatabaseHelper(Context context){
        //String name,  SQLiteDatabase.CursorFactory factory, int version) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onOpen(SQLiteDatabase db) {
            super.onOpen(db);
            if (!db.isReadOnly()) {
                // Enable foreign key constraints
                db.execSQL("PRAGMA foreign_keys=ON;");
            }
        }

        @Override
        public void onCreate(SQLiteDatabase db) {

                db.execSQL(CREATE_USER_TABLE);
                db.execSQL(CREATE_PLAYER_TABLE);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(DROP_USER_TABLE);
        db.execSQL(DROP_PLAYER_TABLE);
        onCreate(db);
        }



        // Adding a user to Users table
        public void addUser(User user){
            SQLiteDatabase db = this.getWritableDatabase();
            ContentValues values = new ContentValues();
            values.put(COLUMN_USER_NAME, user.getName());
            values.put(COLUMN_USER_EMAIL, user.getEmail());
            values.put(COLUMN_USER_PASSWORD, user.getPassword());
            values.put(FOREIGN_PLAYER_ID, user.getForeignID());

            db.insert(TABLE_USER, null, values);
            db.close();
        }

        // Adding a player to players table

        public void addPlayer(Player player) {

            SQLiteDatabase db = this.getWritableDatabase();
            ContentValues values = new ContentValues();


            // Table 2 : Add players info
            values.put(COLUMN_PLAYER_NAME, player.getPlayerName());
            values.put(COLUMN_PLAYER_AGE, player.getPlayerAge());
            values.put(COLUMN_PLAYER_HEIGHT, player.getPlayerHeight());
            values.put(COLUMN_PLAYER_WEIGHT, player.getPlayerWeight());
            values.put(FOREIGN_PLAYER_ID, player.getForeignKey());

            db.insert(TABLE_PLAYERS, null, values);
            db.close();

        }

        // Checking the users email
        public boolean checkUser(String email){
            String[] columns = {
                    COLUMN_USER_ID

            };
            SQLiteDatabase db = this.getWritableDatabase();
            String selection = COLUMN_USER_EMAIL + " = ?";
            String[] selectionArgs = { email };

            Cursor cursor = db.query(TABLE_USER,
                    columns,
                    selection,
                    selectionArgs,
                    null,
                    null,
                    null);
            int cursorCount = cursor.getCount();
            cursor.close();
            db.close();

            if (cursorCount > 0){
                return true;
            }
            return false;
        }

        //
        public String getColumnUserName(String email){

            String user = "";
            String[] columns = {
                    COLUMN_USER_ID

            };
            SQLiteDatabase db = this.getWritableDatabase();
            String selection = COLUMN_USER_EMAIL + " = ?";
            String[] selectionArgs = { email };

            Cursor cursor = db.query(TABLE_USER,
                    columns,
                    selection,
                    selectionArgs,
                    null,
                    null,
                    null);
            int cursorCount = cursor.getCount();


            if (cursor.moveToFirst()) // data?{
              user =  cursor.getString(cursor.getColumnIndex("EMAIL"));

            cursor.close(); // that's important too, otherwise you're gonna leak cursors
            db.close();

            if (cursorCount > 0){
                return user;
            }
            return user;
        }

        // Checking the users email and password
        public boolean checkUser(String email, String password){
            String[] columns = {
                    COLUMN_USER_ID

            };
            SQLiteDatabase db = this.getWritableDatabase();
            String selection = COLUMN_USER_EMAIL + " = ?" + " AND " + COLUMN_USER_PASSWORD + " =?";
            String[] selectionArgs = { email, password };

            Cursor cursor = db.query(TABLE_USER,
                    columns,
                    selection,
                    selectionArgs,
                    null,
                    null,
                    null);
            int cursorCount = cursor.getCount();
            cursor.close();
            db.close();

            if (cursorCount > 0){
                return true;
            }
            return false;
        }
    }

2) Players.java

    public class Players extends AppCompatActivity {

        private Button insert;
        private static final int PICK_IMAGE=100;
        private String nameFromIntent = "";

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_players);

            //Open add players section
            insert = (Button) findViewById(R.id.addPlayer);
            insert.setOnClickListener(new View.OnClickListener()

            {

                @Override
                public void onClick (View v)

                {
                    openaAddPlayersActivity();       
                }
            });
            nameFromIntent = getIntent().getStringExtra("EMAIL");        
        }

        private void openaAddPlayersActivity() {

            Intent intent = new Intent(this, addPlayers.class );
            String nameFromIntent = getIntent().getStringExtra("EMAIL");
            intent.putExtra(("EMAIL") ,nameFroenter code heremIntent);
            startActivity(intent);
        }        
    }

3)addPlayers.java

public class addPlayers extends AppCompatActivity implements View.OnClickListener{

    private Button insert;
    private static final int PICK_IMAGE=100;

    private final AppCompatActivity activity = addPlayers.this;    
    private EditText editTextPlayerName;
    private EditText editTextPlayerAge;
    private EditText editTextPlayerWeight;
    private EditText editTextPlayerHeight;  
    private TextInputEditText textInputEditTextEmail;
    private Inputvalidation inputvalidation;
    private DatabaseHelper databaseHelper;
    private Player player;
    private Button appCompatButtonRegister;
    private User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_players);
       // insert = (Button) findViewById(R.id.profilePicture);
       // insert.setOnClickListener(new View.OnClickListener()

        getSupportActionBar().hide();

        initViews();
        initListeners();
        initObjects();

    }
    private void initViews() {


        editTextPlayerName = (EditText) findViewById(R.id.playerName);
        editTextPlayerAge = (EditText) findViewById(R.id.playerAge);
        editTextPlayerHeight = (EditText) findViewById(R.id.playerHeight);
        editTextPlayerWeight = (EditText) findViewById(R.id.playerWeight);
        textInputEditTextEmail = (TextInputEditText) findViewById(R.id.enterEmail);
        appCompatButtonRegister = (Button) findViewById(R.id.savePlayer);

    }

    private void initListeners() {

        appCompatButtonRegister.setOnClickListener(this);   
    }

    private void initObjects() {   
        inputvalidation = new Inputvalidation(activity);
        databaseHelper = new DatabaseHelper(activity);
        player = new Player ();    
    }

             // Table 2 : Add players info

            @Override
            public void onClick(View v) {
               // Intent intent = new Intent(Intent.ACTION_PICK, Uri.parse("content://media/internal/images/media"));
                //startActivityForResult(intent, PICK_IMAGE);

                switch (v.getId()){
                    case R.id.savePlayer:
                        postDataToSQLite();
                        break;
            }
    }

    private void postDataToSQLite() {


        if(!databaseHelper.checkUser(editTextPlayerName.getText().toString().trim()))
        //textInputEditTextPassword.getText().toString().trim()))
        {
            Bundle email= getIntent().getExtras();
            String a = databaseHelper.getColumnUserName(email.getString("EMAIL"));

            player.setPlayerName(editTextPlayerName.getText().toString().trim());
            player.setPlayerAge(Integer.parseInt(editTextPlayerAge.getText().toString().trim()));
            player.setPlayerHeight(Integer.parseInt(editTextPlayerHeight.getText().toString().trim()));
            player.setPlayerWeight(Integer.parseInt(editTextPlayerWeight.getText().toString().trim()));
            player.setForeignKey(Integer.parseInt(a));

            //Integer.parseInt(databaseHelper.getColumnUserName(ContactsContract.CommonDataKinds.Email.getString("EMAIL"))));
            databaseHelper.addPlayer(player);

            Snackbar.make(findViewById(R.id.addPlayer), R.string.success_player_message,Snackbar.LENGTH_LONG).show();
           // emptyEditText();    
            Intent accountIntent = new Intent(activity, Players.class);
            accountIntent.putExtra("EMAIL", textInputEditTextEmail.getText().toString().trim());
            //emptyInputEditText();
            startActivity(accountIntent);    
        }    
        //else {
            // Snack Bar to show error message that record already exists
          //  Snackbar.make(findViewById(R.id.Register), getString(R.string.error_email_exists), Snackbar.LENGTH_LONG).show();
       // }    
    }

    /*protected void onActivityResult(int requestCode, int resultCode, Intent data){
        super.onActivityResult(requestCode, resultCode, data);
        if(resultCode==RESULT_OK && requestCode==PICK_IMAGE){
            Uri uri = data.getData();
            String x = getPath(uri);
            Toast.makeText(getApplicationContext(), x, Toast.LENGTH_LONG).show();
        }
    }

    private String getPath(Uri uri) {
        if(uri==null)return null;
        String [] projection = {MediaStore.Images.Media.DATA};
        Cursor cursor = managedQuery(uri, projection, null, null, null);
        if(cursor!=null){
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        }
        return uri.getPath();
    }
*/

}

4) Login.java

public class LoginActivity extends AppCompatActivity implements View.OnClickListener {


   private final AppCompatActivity activity = LoginActivity.this;

    private NestedScrollView nestedScrollView;

    private TextInputLayout textInputLayoutEmail;
    private TextInputLayout textInputLayoutPassword;

    private TextInputEditText textInputEditTextEmail;
    private TextInputEditText textInputEditTextPassword;

    private AppCompatButton appCompatButtonLogin;
    private AppCompatTextView textViewLinkRegister;

    private Inputvalidation inputvalidation;
    private DatabaseHelper databaseHelper;

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        getSupportActionBar().hide();

        initViews();
        initListeners();
        initObjects();    
    }

    private void initViews() {

       textInputLayoutEmail = findViewById(R.id.textInputLayoutEmail);
       textInputLayoutPassword = findViewById(R.id.textInputLayoutPassword);

       textInputEditTextEmail = findViewById(R.id.enterEmail);
       textInputEditTextPassword = findViewById(R.id.enterPassword);

       appCompatButtonLogin = findViewById(R.id.Login);
       textViewLinkRegister = findViewById(R.id.textViewLinkRegister);

    }

    private void initListeners() {

        appCompatButtonLogin.setOnClickListener(this);
        textViewLinkRegister.setOnClickListener(this);
    }

    private void initObjects() {

        databaseHelper = new DatabaseHelper(activity);
        inputvalidation = new Inputvalidation(activity);
    }

    @Override
    public void onClick(View v){

        switch (v.getId()){

            case R.id.Login:
            verifyFromSQLite();
            break;

            case R.id.textViewLinkRegister:
                Intent intentRegister = new Intent(getApplicationContext(), Register.class);
                startActivity(intentRegister);
                break;   
        }
    }

    private void verifyFromSQLite() {

       if (!inputvalidation.isInputEditTextFilled(textInputEditTextEmail, textInputLayoutEmail, getString(R.string.error_message_email))){
                return;
            }

        if (!inputvalidation.isInputEditTextEmail(textInputEditTextEmail, textInputLayoutEmail, getString(R.string.error_message_email))){
            return;
        }

        if (!inputvalidation.isInputEditTextFilled(textInputEditTextPassword, textInputLayoutPassword, getString(R.string.error_message_password))){
            return;
        }

        if(databaseHelper.checkUser(textInputEditTextEmail.getText().toString().trim(), textInputEditTextPassword.getText().toString().trim()))
        {

            Intent accountIntent = new Intent(activity, LoggedIn.class);
            accountIntent.putExtra("EMAIL", textInputEditTextEmail.getText().toString().trim());
            emptyInputEditText();
            startActivity(accountIntent);    
        }else {
            Snackbar.make(findViewById(R.id.Login), R.string.error_valid_email_password,Snackbar.LENGTH_LONG).show();
                    //nestedScrollView, getString(R.string.error_valid_email_password), Snackbar.LENGTH_LONG).show();
            }
        }

    private void emptyInputEditText() {

        textInputEditTextEmail.setText(null);
        textInputEditTextPassword.setText(null);

    }
}

【问题讨论】:

  • 我得到以下错误 什么错误? (请编辑您的问题以包含您收到的错误)。

标签: javascript java android sql sqlite


【解决方案1】:

我相信您的问题可能是您的外键正在按应有的方式运行,并且由于传递给 addPlayer 方法的 player 没有' 似乎没有设置用户(除非在 Player 对象的构造中设置圆顶)。

user 很可能为 null 或不是存储在 UserUser_id 列中的值的其他值表。

也就是说,您似乎只是将 email 从一个活动传递到另一个活动,然后只使用 checkUser(只返回一个布尔值)和 getColumnsUserName(仅返回一个字符串,该字符串似乎是根据用作搜索参数的电子邮件找到的电子邮件)。

但是,User_id 必须是整数值,才能成为 User 表中的有效 User_id 列。

  • 也就是说,使用 INTEGER PRIMARY KEY(带或不带 AUTOINCREMENT)定义的 User_id 列是隐藏 rowid 列的别名,并且 必须 strong> 是一个整数值(SQLite Autoincrement PS 另外请注意关于使用 AUTOINCREMENT 的摘要)。

确定问题

我建议在 DatabaseHelper 中的 db.insert(TABLE_PLAYERS, null, values); 行上放置一个断点并在 Debug 中运行,当到达断点时检查 playerforeignId 的值强>对象。

您不妨阅读Debug your app

但是,如果怀疑原因,我也相信堆栈跟踪也应该表明冲突。

我建议传递 User_id 值,而不是将 email 从一个活动传递到另一个活动,因为这将是唯一的,也是定位相应的行:-

rowid 表的数据存储为 B-Tree 结构,其中包含 每个表行都有一个条目,使用 rowid 值作为键。这 表示按 rowid 检索或排序记录很快。搜索 对于具有特定 rowid 的记录,或对于具有 rowids 的所有记录 在指定范围内的速度大约是类似搜索的两倍 通过指定任何其他 PRIMARY KEY 或索引值来生成。 ROWIDs and the INTEGER PRIMARY KEY

附加

有两个问题会导致索引 -1 问题。

-1 问题本身是因为如果传递给该方法的列在 Cursor 中不存在,Cursor getColumnIndex 方法返回 -1(请注意,Cursor 只有已指定的列) .

第一个问题是:-

user =  cursor.getString(cursor.getColumnIndex("EMAIL"));

用户表中没有这样的列,所以这总是会失败。将其更改为:- 用户 = cursor.getString(cursor.getColumnIndex(COLUMN_USER_EMAIL));

将指定表中的列。

第二个问题是,虽然 COLUMN_USER_EMAIL 是表中的有效列,但该列不包含在游标中。

要在光标中包含该列,然后更改:-

        String[] columns = {
                COLUMN_USER_ID

        };

到:-

    String[] columns = {
            COLUMN_USER_ID,
            COLUMN_USER_EMAIL

    };

或到:-

    String[] columns = {"*" }; //<<<<<<<<<< * means ALL columns

或者改为更改:-

    Cursor cursor = db.query(TABLE_USER,
            columns,
            selection,
            selectionArgs,
            null,
            null,
            null);
    int cursorCount = cursor.getCount();

    Cursor cursor = db.query(TABLE_USER,
            null, //<<<<<<<<<< null equates to * and thus ALL columns
            selection,
            selectionArgs,
            null,
            null,
            null);

【讨论】:

  • 感谢您的快速回复,真的没想到这么快。所以我相信你可以猜到这是我第一次使用 android studio 制作应用程序,而这只是为了提高技能和学习新技术。我会试一试,让你知道我过得怎么样,谢谢一百万:)
  • @EamonMac -1 可能是由于在 getColumnIndex 方法中找不到列名。所以根本问题将在 getColumnUserName 方法中。而不是user = cursor.getString(cursor.getColumnIndex("EMAIL")); 使用user = cursor.getString(cursor.getColumnIndex(COLUMN_USER_EMAIL));(如果我输入正确的话)。 (即列名是 User_email 而不是 EMAIL)
  • 嗨迈克,所以我添加了你提到的断点,但是那个类 databasehelper 没有得到它的断点命中。我已经用我看到的错误更新了这个问题,这可以解释为什么我的断点没有被击中 当我从 addPlayers.java 类中删除这两行代码时,断点被击中并将foreignKey 显示为“0”。第 120 行捆绑电子邮件= getIntent().getExtras();字符串 a = databaseHelper.getColumnUserName(email.getString("EMAIL"));我使用此代码尝试设置 foreignKey 字段。
  • 听起来你可以忽略我的怀疑,使用正确的列(根据评论)名称,它可能会奏效。
  • 您好,非常感谢您到目前为止的帮助:) 所以在我的 addPlayer.java 类的 postDataToSQL() 方法中,这些行似乎是问题第 120 行 - Bundle email= getIntent().getExtras() ;字符串 a = databaseHelper.getColumnUserName(email.getString("EMAIL"));一旦它到达第二行,它就会进入“Looper.java”类。 DatabaseHelper.java 中的 getColumnUserName 方法可能是问题所在。在我对此进行编码之前,外键已为每个玩家自动设置为“0”。但它仍在将播放器添加到数据库中。现在它甚至没有将播放器添加到数据库中。
【解决方案2】:

因此,该应用在重建后现在可以正常运行。 很奇怪的行为,但我不会抱怨。 谢谢你的帮助。

埃蒙

【讨论】:

    最近更新 更多