22

我有两个具有 1:n 关系的表,我正在使用内容提供程序和 cursorloader。

我将如何进行连接查询以使用游标加载器?我可以在内容提供程序中使用 rawSql 以某种方式破解它,但是如何在游标加载器构造函数中做到这一点超出了我的范围。

非常感谢 !

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

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

4

2 回答 2

31

Uri不指向任何表。它指向你想要指向的任何东西。

让我们假设你的两张桌子是Customerand Order。一位客户可能有很多订单。您想要执行查询以获取所有未完成的订单……但您想要加入一些您需要的与客户相关的列,例如客户的姓名。

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

你有两个选择:

  1. 在您的/order Uri. 拥有另一个可用列可能不会破坏提供者的任何现有消费者(尽管测试总是一个好主意)。这就是ContactsContract它的作用——它在几乎所有表的所有查询中加入一些基本列,例如联系人的姓名。

  2. 创建content://your.authority.goes.here/orderWithCust它执行相同的基本查询/order,但包含您的联接。在这种情况下,您可以使用insert(),update()delete()抛出某种RuntimeException, 来提醒您不应该使用/orderWithCustas来修改数据Uri

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

于 2012-12-30T12:53:34.530 回答
4

我找到了使用 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);
于 2014-12-13T23:11:28.443 回答