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



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

如何使连接查询与游标加载器一起工作?我可以用rawSql在内容提供程序中破解它,但如何在游标加载器构造函数中做到这一点超出了我的能力。

谢谢你!

CursorLoader(Context Context, Uri Uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

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

Uri没有指向任何表。它指向你想指向的任何地方。

假设您的两个表是CustomerOrder。一个客户可能有很多订单。你想要执行一个查询来获取所有未完成的订单…但是您想要加入一些您需要的与客户相关的列,例如客户的姓名。

让我们进一步假设您已经定义了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,以提醒您不应该将/orderWithCust用作Uri来修改数据。

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

我找到了一个使用ContentProvider子类的解决方案。假设有表格tblA和另一个表格tblB。我建议创建两个类"AContentProvider"one_answers"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);

相关内容

  • 没有找到相关文章

最新更新