【问题标题】:How to use correctly foreign keys in Android, using SQLite and OrmLite如何在 Android 中正确使用外键,使用 SQLite 和 OrmLite
【发布时间】:2012-11-09 17:17:16
【问题描述】:

首先,我用这 2 个表创建了数据库: 地址和电话。

我已经使用 Ormlite 在 android 中实现了外键,以便建立从 Adresse 到 Telephones 的连接 1。

电话的代码:

@DatabaseTable(tableName = "TELEPHONES")
public class Telephone {
    public static final String TABLE_NAME = "TELEPHONES";
    public static final String ID_ADRESSE = "ID_ADRESSE";

    @DatabaseField(generatedId = true)
    private Integer _id;

    @DatabaseField(canBeNull = false, foreign = true,columnName = ID_ADRESSE)
    private Adresse adresse; 
        .
        .
        .
        .
    public Adresse getAdresse() {
        return adresse;
    }

    public void setAdresse(Adresse adresse) {
        this.adresse = adresse;
    }  
}

地址代码:

@DatabaseTable(tableName = "ADRESSE")
public class Adresse {

    public static final String TABLE_NAME = "ADRESSE";
    public static final String ID = "_id";

    @DatabaseField(generatedId = true)
    private Integer _id;

    @ForeignCollectionField(eager = false)
    private ForeignCollection<Telephone> telephones;
}

我还读到 SQLite 数据库实现了外键,但是每次打开数据库时都必须启用它们才能修改它。 所以我添加了这段代码:

.
.
.
    public void openDataBase() {
        // Open the database
        String myPath = DB_PATH + DB_NAME;
        myDataBase = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READWRITE);
        if (!myDataBase.isReadOnly()) {
            myDataBase.execSQL("PRAGMA foreign_keys=ON;");
        } else {
            System.out.println("database is open as read only");
        }
    }
.
.
.

问题是,通常如果我想删除一个有一个或多个电话的地址,外键约束不应该让我这样做,但没有任何反应。 没有错误,没有警告,什么都没有。 当我在数据库中查看我是否删除了地址时,我看到地址已被删除,而电话仍然存在,并且 id_adresse 链接到我已删除的那个。

我已经用 Firefox 的 SQLite Manager 打开了数据库,当我尝试做同样的事情时,出现一个错误,告诉我,由于外键无法做到这一点......

差点忘了:

Sqlite中Telephone表的代码:

CREATE TABLE "TELEPHONES" 
("_id" INTEGER PRIMARY KEY  NOT NULL,"ID_ADRESSE" INTEGER REFERENCES ADRESSE(_id))

所以我的最后一个问题是:

我做错了什么,因为在 Android 中我可以删除地址?

我想要的是正确实现外键,如果不先删除与地址相关的电话,就无法删除地址。

更新: 我试过这样做:

public void openDataBase() {
    // Open the database
    String myPath = DB_PATH + DB_NAME;
    myDataBase = SQLiteDatabase.openDatabase(myPath, null,
            SQLiteDatabase.OPEN_READWRITE);
    if (!myDataBase.isReadOnly()) {
        myDataBase.execSQL("PRAGMA foreign_keys=ON");
        myDataBase.execSQL("DELETE FROM ADRESSE WHERE _id=8");
    } 
}

它确实删除了地址以及相关的电话。

那么为什么要使用 ormlite 命令:

    DeleteBuilder<Adresse, Integer> db = daoAdresse.deleteBuilder();
db.where().eq(Adresse.ID, 8);
daoAdresse.delete(db.prepare());

事务里面没有工作?

更新 2:

@Override
    public void onOpen(SQLiteDatabase myDatabase){
        String myPath = DB_PATH + DB_NAME;
        myDataBase = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READWRITE);
        if (!myDataBase.isReadOnly()) {
            myDataBase.execSQL("PRAGMA foreign_keys=ON");
            System.out.println("open database with pragma on from onOpen");
        } else {
            System.out.println("database is open as read only from onOpen");
        }

    }

我这样做了,我收到消息说使用了这种方法,而不是另一种方法,但只是删除了我的地址,没有电话。所以我真的不知道。一定是某个地方出了问题,而且我觉得跟DeleteBuilder有关……

仍在寻找中..

【问题讨论】:

  • 我们可以编写触发器并强制执行外键约束。
  • 如果要删除TELEPHONES中的内容,则将ON DELETE CASCADE添加到外键定义中。

标签: android sqlite ormlite


【解决方案1】:

据我所知,支持外键限制,但您必须明确设置。 This answer 可能会对您有所帮助。请注意,正如那里的 cmets 所述,它仅适用于 Android 2.2 及更高版本。

更新

您尚未定义更新/删除操作。在Telephone 中,将您的列定义更新为以下内容:

@DatabaseField(canBeNull = false, foreign = true, columnDefinition = "integer references ADRESSE(_id) on delete cascade")
private Adresse adresse; 

然后重新创建您的数据库。注意“on delete cascade”;当 ADRESSE 中的一行被删除时,TELEPHONES 中的所有相关条目都应该被删除。

【讨论】:

  • 我使用的是 Android 4.0.3,我在上面写过。我设置了“PRAGMA foreign_keys=ON;”每次打开数据库。
  • 抱歉,忽略了这一点。在添加 myDataBase.execSQL("PRAGMA foreign_keys=ON;"); 之前,您是否有机会创建表?
  • 我实现了这个,没有任何反应:地址被删除,但电话没有。我唯一的猜测是该命令没有打开外键,或者我应该将该命令放在其他地方......
  • @user1809672 我有工作外键并使用db.execSQL("PRAGMA foreign_keys = ON") (我怀疑额外的; 会改变任何东西,但请随意尝试)在SQLiteOpenHelper#onOpen 中,它的作用与您的@987654328 大致相同@。如果数据库具有实际上被 OrmLite 违反的外键约束,那么可能发生的唯一方法是未设置或关闭编译指示。检查 OrmLite 是否在每次打开与数据库的新连接时都使用您的方法
  • 您是否重新创建了表格?
猜你喜欢
  • 1970-01-01
  • 2014-09-28
  • 1970-01-01
  • 2021-12-14
  • 1970-01-01
  • 2012-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多