当CursorLoader的构造函数不支持它时如何使用连接查询

我有两个1:n关系的表,我使用内容提供者和光标加载器。

我如何使加入查询与光标加载器一起工作? 我可以用内部提供程序中的rawSql以某种方式破解它,但是如何在游标加载器构造函数中执行它却超出了我的想象。

非常感谢 !

CursorLoader(上下文上下文,Uri uri,String []投影,字符串选择,String [] selectionArgs,String sortOrder)

当Uri只能指向一个表时,如何查询连接


Uri没有指向任何桌子。 它指向你想要指向的任何东西。

让我们假装你的两个表是CustomerOrder 。 一个客户可能有很多订单。 您希望执行查询以获取所有未完成的订单......但是您想加入一些您需要的与客户相关的列,例如客户的名称。

让我们进一步假设您已经有content://your.authority.goes.here/customercontent://your.authority.goes.here/order定义为纯粹查询这些表。

你有两个选择:

  • 在您的/order Uri上添加客户显示名称的加入。 有另一个可用的列可能不会破坏提供者的任何现有消费者(尽管测试总是一个好主意)。 这就是ContactsContract所做的事情 - 它在所有表的几乎所有查询中加入一些基本列,如联系人的姓名。

  • 创建content://your.authority.goes.here/orderWithCust ,它执行与/order相同的基本查询,但包含您的连接。 在这种情况下,可以使用insert()update()delete()引发某种RuntimeException ,以提醒您不应使用/orderWithCust作为Uri修改数据。

  • 最终,设计ContentProvider Uri系统与设计REST Web服务的URL系统类似。 在这两种情况下,连接都必须在提供者/服务器端完成,因此您可能需要中断一个表到一个URL的基线以提供一些有用的连接。


    我找到了一个使用ContentProvider的子类的解决方案。 假设你有表tblA和另一个表tblB。 我建议创建两个类“AContentProvider”和“BContentProvider”。 最重要的是,确保两个表都设置在同一个数据库中。

    解决方案的主要部分是覆盖ContentProvider中的ContentProvider.query(),您将从CursorLoader调用 - URI决定它是哪一个:

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sort) {
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
    
        qb.setTables(
                "tblA LEFT JOIN tblB"
                        + " ON ("
                        + "tblA.b_id"
                        + " = "
                        + "tblB.id"
                        + ")"
        );
    
        ...
        // Content of projection is set by CursorLoader
        // usually in an Activity that implements LoaderManager.LoaderCallbacks<>
    
        Cursor c = qb.query(
                database,
                projection,
                selection,
                selectionArgs,
                groupBy,
                having,
                orderBy
        );
    
        ...
        return c;
    }
    

    正如你所看到的, JOIN是在setTables()中完成的 。 使用投影你确保你只显示你真正需要的列,最重要的是,你没有重复的列,比如两个表中的“id”:

    final String[] projection = new String[] {
            "tblA.*",
            "tblB.columnThatOnlyBHas"
    };
    

    利用覆盖并尽可能在子类中完成尽可能多的工作; 例如:如果游标结果集更改,我所有重写的query()方法都会调用setNotificationUri()来通知ContentResolver。

    c.setNotificationUri(getContext().getContentResolver(), uri);
    
    链接地址: http://www.djcxy.com/p/31991.html

    上一篇: how to use join query in CursorLoader when its constructor does not support it

    下一篇: ListView example duplicates contacts in result view