在Android上使用SQLite查询和操作游标

22

不确定是否只有我有这种感觉...

我觉得在Android中使用SQLite API非常繁琐和令人沮丧。有没有人有什么技巧或助手可以让我的生活变得更轻松?

这是我所说的问题的例子。

//create code

db.execSQL("CREATE TABLE " + CUSTOMER_TABLE_NAME + " ("
                        + GENERIC_ID_KEY+ " INTEGER PRIMARY KEY NOT NULL, " 
                        + PHONE_KEY + " INTEGER NOT NULL, "
                        + CUSTOMER_NAME_KEY+ " TEXT NOT NULL, "
                        + EMAIL_KEY + " TEXT NOT NULL, "
                        + ADDRESS_KEY +" TEXT);");


//get code
    Cursor mCursor = mDb.query(true, CUSTOMER_TABLE_NAME, new String[] {GENERIC_ID_KEY,
                        ADDRESS_KEY, PHONE_KEY, EMAIL_KEY,CUSTOMER_NAME_KEY}, GENERIC_ID_KEY + "=" + customerDbId, null,
                                null, null, null, null);

        Customer customer = new Customer (customerDbId, (CharSequence)mCursor.getString(mCursor.getColumnIndexOrThrow(CUSTOMER_NAME_KEY)),
                            (CharSequence)mCursor.getString(mCursor.getColumnIndexOrThrow(PHONE_KEY)),
                            (CharSequence)mCursor.getString(mCursor.getColumnIndexOrThrow(EMAIL_KEY)),
                            (CharSequence)mCursor.getString(mCursor.getColumnIndexOrThrow(ADDRESS_KEY)));

这是一个简单的示例,展示如何从数据库查询创建一个简单的客户端对象;我的一些代码比这更加丑陋。以这种方式手动编写查询会导致各种错误,在运行时才能发现。

非常感谢任何提示!

好的,在下面的提示之后,我现在有了这个:

  db.execSQL("CREATE TABLE customer (_id INTEGER PRIMARY KEY NOT NULL, " 
                        + "phone_number INTEGER NOT NULL, "
                        + "name TEXT NOT NULL, "
                        + "email TEXT NOT NULL, "
                        + "address TEXT);");


    //get code
String q = "SELECT * FROM customer WHERE _id = " + customerDbId +";"
        Cursor mCursor = mDb.rawQuery(q, null);

        Customer customer = new Customer (mCursor);

在Customer中,我通过以下方式访问字段:

mName = cursor.getString(2)

啊,我感觉好多了 :)

干杯 Si


1
没有冒犯的意思,有时你确实需要编写一些代码 :) 移动平台不能像桌面操作系统那样提供相同的抽象。 - Henrik P. Hessel
7
啊,那个 getColumnIndexOrThrow 真是折磨我啊... 他们不能直接创建一个重载的 getString 方法,并直接使用列名吗? - Thomas Levesque
2个回答

39
  1. 如果没有必要,不要使用模型对象。我得出的结论是,在移动平台上,除非有重要的业务逻辑只能通过模型对象表示,否则它们会带来更多麻烦而不值得。
  2. 假设你被迫使用模型对象,请让它们从Cursor中加载自己,而不是尝试传入无数参数。
  3. 如果你懂SQL,query()相对于rawQuery()来说更冗长,但增加的价值很有限。
  4. 通过连接字符串来组装CREATE TABLE子句,这是自找的痛苦,而不是SQLite或Android所规定的。
  5. 不要从自定义代码中使用getColumnIndexOrThrow()。你编写了查询语句,因此你知道列返回的顺序。只有在创建一些不知道所给出的Cursor的细节的抽象库时,才应该使用类似getColumnIndexOrThrow()的方法。
  6. String继承自CharSequence,所以所有这些强制类型转换都可以省略。

谢谢,rawQuery()!我错过了它,看起来非常有用。我还会重新考虑我的模型对象,因为我不会被它们束缚。 - longhairedsi
2
在我自己摸索之前的几周里,你在哪里?很高兴得到了我已经怀疑的确认,但遗憾的是,所有的谷歌文档似乎都遵循这种极其复杂的路线。 - Fergal Moran
嗨,CommonsWare,您能否确认我的理解是否正确?您是说当使用游标作为数据对象时,建模对象不是必需的,除非您需要操作数据,否则只需使用游标?在我的SQLite支持的应用程序中,我很少使用建模对象,因为我已经将我的SQLite表建模成“对象”,当我将其作为游标返回时,那似乎就是我所需要的全部。您同意吗?如果您需要更多细节,这是我的问题:http://stackoverflow.com/questions/9791349/oop-modelled-objects-in-a-database-driven-app - AutoM8R
使用模型的替代方案是什么? - Kaloyan Roussev
@J.K.: 首先,请记住这个问题和答案已经五年了,在Android领域这是一个漫长的时间。假设您愿意处理内存管理,您可以通过手动或通过面向Android的ORM将数据库结果复制到POJO模型中。但是您并不绝对需要POJO模型,只需使用原始的“Cursor”作为模型数据的来源即可。 - CommonsWare
太好了,因为我总是将我的数据库操作类放在单独的文件中,并通过监听器发送查询结果 :) - Kaloyan Roussev

3

在将SQL语句复制到Android字符串之前,我在SQLite中测试了很多。这样做可以让我更轻松地调试,因为我可以直接与命令行交互。

我使用的另一种技术是尽可能将我的查询保存为字符串常量或字符串资源。

你不需要使用诸如INTEGER NOT NULL这样的SQL语句,因为SQLite使用鸭子类型/显式类型。尽管如此,它确实有助于类型亲和性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接