如何实现具有多个表的内容提供程序?

时间:2014-05-24 14:50:38

标签: android android-contentprovider

更新:在我看来"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列的主题表。 我想让Notes表包含列_id和外键Topic_id和Note_text。

如何设计主题和备注?

但是看看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;

3 个答案:

答案 0 :(得分:10)

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

访问所有图书

content://org.example.bookprovider/books

按ID

访问图书
content://org.example.bookprovider/books/#

按作者姓名访问图书

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

根据需要创建尽可能多的URI,这取决于您。这样,您的提供商的用户可以非常轻松地访问您的数据库信息,也许这就是为什么您会得到供应商旨在使用一个表数据库的印象,但不是,内部是工作完成的地方。

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

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;
}

希望它有所帮助。

答案 1 :(得分:1)

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

ContentProvider旨在(其中一个目标)包装访问您的表格。数据库模式的设计由您决定。

通常,您需要:

  1. 定义表/它应该通过在类中执行sql命令来扩展SQLiteOpenHelper
  2. 为他们定义一个uri
  3. 为NOTE_ID
  4. 制作此表的查询逻辑

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

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

答案 2 :(得分:0)

以下是使用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'