【问题标题】:How to implement a content provider with more than one table?如何实现具有多个表的内容提供程序?
【发布时间】:2014-05-24 14:50:38
【问题描述】:

更新:看着"vnd.android.cursor.dir/vnd.google.note""vnd.android.cursor.item/vnd.google.note",在我看来,光标好像是针对一张桌子的。

从示例中可以看出,内容提供程序似乎设计为与一张表一起使用。我确实知道如何在 sqlite 中使用多个表,但在我看来,内容提供者似乎是要从一个表中选择一行或多行。

http://developer.android.com/guide/topics/providers/content-provider-creating.html

另外,请参阅 adt-bundle-windows-x86-20131030\sdk\samples\android-19\legacy\NotePad\src\com\example\android\notepad 中的记事本示例

假设我想按主题做笔记。

我想要一个包含 _id 和 Title_text 列的主题表。 我想要带有 _id 列和外键 Topic_id 和 Note_text 的 Notes 表。

如何设计主题和注释?

但是查看 Notes 示例、内容提供程序上的内容 URI 和文档,似乎拥有多个相关表是事后才想到的,对我来说并不明显。

来自 NotepadProvider.java、Notepad.java:

    public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.note";

        /**
         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
         * note.
         */
        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.note";

                public static final Uri CONTENT_ID_URI_BASE
            = Uri.parse(SCHEME + AUTHORITY + PATH_NOTE_ID);

        /**
         * The content URI match pattern for a single note, specified by its ID. Use this to match
         * incoming URIs or to construct an Intent.
         */
        public static final Uri CONTENT_ID_URI_PATTERN
            = Uri.parse(SCHEME + AUTHORITY + PATH_NOTE_ID + "/#");



               @Override
   public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
           String sortOrder) {
            ...
                   switch (sUriMatcher.match(uri)) {

           // If the incoming URI is for notes, chooses the Notes projection
           case NOTES:
               qb.setProjectionMap(sNotesProjectionMap);
               break;

           /* If the incoming URI is for a single note identified by its ID, chooses the
            * note ID projection, and appends "_ID = <noteID>" to the where clause, so that
            * it selects that single note
            */
           case NOTE_ID:
               qb.setProjectionMap(sNotesProjectionMap);
               qb.appendWhere(
                   NotePad.Notes._ID +    // the name of the ID column
                   "=" +
                   // the position of the note ID itself in the incoming URI
                   uri.getPathSegments().get(NotePad.Notes.NOTE_ID_PATH_POSITION));
               break;

【问题讨论】:

  • 所以你不知道如何在sqlite中使用多个表?
  • @pskink 我当然知道如何在 sqlite 中使用多个表。内容提供者似乎是要从一张表中选择一行或多行。
  • 为什么是一张桌子?只返回一个从多个表中选择行的游标,这里有什么问题?
  • “如何设计主题和注释?” - 您粘贴的代码的方式将是一种方法。您可能会考虑查看具有提供程序的 AOSP 应用程序,以了解在这些应用程序中如何处理它们。在android contentprovider "multiple tables" 上进行 Google 搜索会发现更多想法,包括一些重复的 SO 问题,例如 stackoverflow.com/questions/13572352/…stackoverflow.com/questions/3814005/…
  • @pskink 看着 "vnd.android.cursor.dir/vnd.google.note""vnd.android.cursor.item/vnd.google.note" 似乎光标是针对一张桌子的。

标签: android android-contentprovider


【解决方案1】:

创建ContentProvider 时,期望其他应用程序将使用您的数据库,我的意思是其他对您的数据库方案一无所知的人。为了方便他们,您可以创建并记录您的 URI:

访问所有书籍

content://org.example.bookprovider/books

通过 id 访问书籍

content://org.example.bookprovider/books/#

按作者姓名访问书籍

content://org.example.bookprovider/books/author

根据需要创建尽可能多的 URI,这取决于您。通过这种方式,您的 Provider 的用户可以非常轻松地访问您的数据库信息,也许这就是为什么您会觉得 Provider 旨在与一个表数据库一起工作,但不,内部是完成工作的地方。

在您的 ContentProvider 子类中,您可以使用 UriMatcher 来识别将传递给您的 ContentProvider 方法的不同 URI(queryinsertupdatedelete)。如果Uri 请求的数据存储在多个表中,您实际上可以使用JOINs 和GROUP BYs 或任何您需要的SQLiteQueryBuilder,例如

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    SQLiteQueryBuilder mQueryBuilder = new SQLiteQueryBuilder();
    . . .   
    String Joins = " t1 INNER JOIN table2 t2 ON t2._id = t1._id"
    + " INNER JOIN table3 t3 ON t3._id = t1._id";

    switch (mUriMatcher.match(uri)) {
        case DATA_COLLECTION_URI:
            mQueryBuilder.setTables(YourDataContract.TABLE1_NAME + Joins);
            mQueryBuilder.setProjectionMap(. . .);
            break;
        case SINGLE_DATA_URI:
            mQueryBuilder.setTables(YourDataContract.TABLE1_NAME + Joins);
            mQueryBuilder.setProjectionMap(. . .);
            mQueryBuilder.appendWhere(Table1._ID + "=" + uri.getPathSegments().get(1));
            break;
        case . . .
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
    }
    . . .
    SQLiteDatabase db = mOpenHelper.getReadableDatabase();
    Cursor c = mQueryBuilder.query(db, projection, selection, selectionArgs, groupBy, having, orderBy);
    return c;
}

希望对你有帮助。

【讨论】:

  • 在你的例子中,投影图可以引用不同的表吗?比如说,t1.book, t2.author
  • 是的,创建一个投影图,映射用户可能从不同表请求的所有列。
【解决方案2】:

对不起,我不明白你的问题。

ContentProvider 旨在(其目标之一)包装对您的表格的访问。数据库模式的设计取决于您。

一般情况下,您需要:

  1. 定义你的表/它应该通过在扩展 SQLiteOpenHelper 的类中执行 sql 命令来完成
  2. 为他们定义一个 uri
  3. 定义查询此表的逻辑,因为它是针对 NOTE_ID 进行的

更新 对于 JOIN 操作,通常使用 SQLiteQueryBuilder。在setTables() 中,您需要使用 JOIN 子句编写表名,例如

.setTables(NoteColumns.TABLENAME +
            " LEFT OUTER JOIN " + TopicColumns.TABLENAME + " ON " +
            NoteColumns.ID + " = " + TopicColumns.ID);

【讨论】:

    【解决方案3】:

    这是我在内容提供程序中使用 projectionMap 进行多表查询的代码

    //HashMap for Projection
     mGroupImageUri = new HashMap<>();
        mGroupImageUri.put(RosterConstants.JID,RosterProvider.TABLE_ROSTER+"."+RosterConstants.JID);
        mGroupImageUri.put(RosterConstants.USER_NAME,RosterProvider.TABLE_ROSTER+"."+RosterConstants.USER_NAME);
        mGroupImageUri.put(ChatConstants.MESSAGE,"c."+ChatConstants.MESSAGE+ " AS "+ ChatConstants.MESSAGE);
        mGroupImageUri.put(ChatConstants.SENDER,"c."+ChatConstants.SENDER+" AS "+ChatConstants.SENDER);
        mGroupImageUri.put(ChatConstants.URL_LOCAL,"c."+ChatConstants.URL_LOCAL+" AS "+ChatConstants.URL_LOCAL);
    
    //case for content type of uri
      case IMAGE_URI:
                qBuilder.setTables(RosterProvider.TABLE_ROSTER
                        + " LEFT OUTER JOIN "+ TABLE_NAME + " c"
                        + " ON c."+ ChatConstants.JID + "=" + RosterProvider.TABLE_ROSTER + "."+RosterConstants.JID);
                qBuilder.setProjectionMap(mGroupImageUri);
                break;
    
        //ContentResolver query for Projection form, selection and selection args
    String[] PROJECTION_FROM = new String[]{
                RosterConstants.JID,
                RosterConstants.USER_NAME,
                ChatConstants.MESSAGE,
                ChatConstants.SENDER,
                ChatConstants.URL_LOCAL
        };
    
        String selection = RosterProvider.TABLE_ROSTER +"."+RosterConstants.JID+ "='" + jid + "' AND " + "c."+ChatConstants.FILE_TYPE+"="+ChatConstants.IMAGE;
        String[] selectionArgu = null;
        String order = "c."+ChatConstants.MESSAGE+" ASC";
    
        Cursor cursor = mContentReolver.query(ChatProvider.CONTENT_URI_GROUP_IMAGE_URI,
                PROJECTION_FROM,selection, null,order);
    
        //@ChatProvider.CONTENT_URI_GROUP_IMAGE_URI = 'your content type uri'
        //@TABLE_NAME = 'table1'
        //@RosterProvider.TABLE_ROSTER ='table2'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-10
      • 2016-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多