2012-12-30 9 views
20

Mam dwie tabele z relacji 1: n, używam dostawcy treści i cursorloader.Jak użyć zapytania sprzężenia w CursorLoader, gdy jego konstruktor go nie obsługuje

Jak utworzyć zapytanie łączące do pracy z programem ładującym kursor? Mogę to jakoś zhackować z dostawcą treści rawSql, ale jak to zrobić w konstruktorze programu ładującego kursor, jest poza mną.

Wielkie dzięki!

CursorLoader (kontekst kontekst Uri URI, String [] projekcyjne, wybór ciąg, ciąg [] selectionArgs, łańcuch sortowanie)

Jak zapytań dla przyłączenia gdy Uri może wskazywać tylko jednej tabeli

Odpowiedz

31

The Uri nie wskazuje żadnej tabeli. Wskazuje na to, na co masz ochotę.

Udawajmy, że twoje dwie tabele to Customer i Order. Jeden klient może mieć wiele zamówień. Chcesz wykonać zapytanie, aby uzyskać wszystkie zaległe zamówienia ... ale chcesz dołączyć do niektórych kolumn związanych z klientem, które będą potrzebne, takich jak nazwa klienta.

Dalej udawajmy, że masz już zdefiniowane content://your.authority.goes.here/customer i content://your.authority.goes.here/order, aby zapytać o czystość tych tabel.

Masz dwie możliwości:

  1. dodać dołączyć nazwy wyświetlacza klienta na /orderUri. Posiadanie kolejnej dostępnej kolumny prawdopodobnie nie naruszy dotychczasowych klientów dostawcy (chociaż testowanie zawsze jest dobrym pomysłem). To właśnie robi ContactsContract - łączy w niektórych kolumnach bazowych, takich jak nazwa kontaktu, prawie we wszystkich kwerendach wszystkich tabel.

  2. Utwórz content://your.authority.goes.here/orderWithCust, który wykonuje to samo podstawowe zapytanie, co /order, ale zawiera twoje sprzężenie. W takim przypadku możesz mieć insert(), update() i delete() wrzucić coś w rodzaju RuntimeException, aby przypomnieć, że nie powinieneś modyfikować danych za pomocą /orderWithCust jako Uri.

W końcu projektowaniu systemu do ContentProviderUri jest podobny do projektowania systemu url Web Service za resztę. W obu przypadkach dołączenie musi zostać wykonane po stronie dostawcy/serwera, więc może być konieczne złamanie bazowego adresu URL tabeli jeden do jednego, aby zaoferować kilka użytecznych połączeń.

+1

czytam odpowiedź wyżej, ale w moim przypadku cały punkt przyłączenia jest przy użyciu kolumny do pobrania z wielu powiązanych tabel za pomocą tylko jednego zapytania. wewnątrz pojedynczego kursora, który otrzymuję z programu ładującego kursory, potrzebuję DISPLAY_NAME_PRIMARY z tabeli KontaktyContract.Contact, ACCOUNT_NAME z tabeli KontaktyContract.RawContact i DATA1 z tabeli ContactsContract.DATA. Teraz nie rozumiem, w jaki sposób pojedynczy Uri może mi pomóc w tym, ponieważ jeśli dam Uri wskazując tabelę ContactsContract.RawContact, a następnie, w jaki sposób mam uzyskiwać dostęp do powiązanych kolumn tabeli ContactContract.Contact i ContactsContract.Data –

+1

@AhhishekChauhan: Cóż, w twoim przypadku nie napisałeś 'ContentProvider', co oznacza, że ​​nie możesz" zhakować tego " jakoś z dostawcą treści rawSql ", jak twierdziłeś w swoim pytaniu. Moja odpowiedź jest skierowana do kogoś, kto pisze "ContentProvider" i dlatego może wykonać join wewnątrz tego. W twoim przypadku będziesz musiał ręcznie "połączyć" swoje dane z wielu obiektów 'Cursor', a framework' Loader' nie pomoże wiele w tym obszarze. Poza mankietem użyłbym 'AsyncTask', a następnie zapytań używających' ContentResolver' i scalenia twoich danych w 'doInBackground()', jak sądzę. – CommonsWare

+0

ya ... dziękuję, wykorzystam do tego asynctask i scalę później ... ten będzie mi odpowiadał lepiej –

4

Znalazłem rozwiązanie przy użyciu podklasy ContentProvider. Załóżmy, że masz tabelę tblA i inną tabelę tblB. Polecam tworzenie dwóch klas "AContentProvider" i "BContentProvider". Co najważniejsze, upewnij się, że obie tabele są skonfigurowane w tej samej bazie danych.

Główną częścią rozwiązania jest przesłonić ContentProvider.query() w ContentProvider że zadzwonisz z CursorLoader - URI decyduje, który z nich to:

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

Jak widać, JOIN odbywa się w setTables().Korzystanie projekcję upewnić się, że tylko wyświetlanie kolumny, które naprawdę potrzebują, a przede wszystkim, nie masz duplikaty kolumn, jak „id” z obu tabel:

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

użytkowania czynią z ręcznym i spróbować wykonać jak najwięcej pracy w pod-klasach; na przykład: wszystkie moje zastąpionej zapytania() metody zadzwonić setNotificationUri(), aby powiadomić ContentResolver Jeśli wynik kursor zestaw zmiany .:

c.setNotificationUri(getContext().getContentResolver(), uri); 
Powiązane problemy