2010-02-05 4 views
10

누구나 SQLite에 일대 다 매핑을 구현하는 방법에 대한 조언이 ContentProvider을 사용합니까? Uri ContentProvider#insert(Uri, ContentValues)을 보면 삽입 할 데이터가 포함 된 ContentValues param이 있음을 알 수 있습니다. 문제는 현재 구현에서 ContentValuesput(String, Object) 메서드를 지원하지 않으므로 클래스가 final이므로 확장 할 수 없습니다. 왜 그것이 문제입니까? 내 디자인은 다음과 같습니다.Android : SQLite 일대 다 디자인

1 대 다 관계에있는 2 개의 테이블이 있습니다. 코드에서이를 나타 내기 위해 2 개의 모델 객체가 있습니다. 1st는 주 레코드를 나타내며 두 ​​번째 객체 인스턴스의 목록 인 필드를가집니다. 이제는 현재 개체에서 생성 된 ContentValues을 반환하는 모델 개체 # 1에 도우미 메서드가 있습니다. ContentValues#put 오버로드 된 메소드로 원시 필드를 채우는 것은 사소한 일이지만 목록에는 운이 없네요. 그래서 현재 두 번째 테이블 행이 단일 문자열 값이므로 쉼표로 구분 된 문자열을 생성 한 다음 ContentProvider#insert 안에 문자열 []로 다시 구문 분석합니다. 그게 기분이 좋으니까, 어쩌면 누군가가 더 깨끗한 방식으로 어떻게 할 수 있는지 암시 할 수 있습니다.

여기에 몇 가지 코드가 있습니다. 모델 클래스의 첫 번째 : 여기

public ContentValues toContentValues() { 
    ContentValues values = new ContentValues(); 
    values.put(ITEM_ID, itemId); 
    values.put(NAME, name); 
    values.put(TYPES, concat(types)); 
    return values; 
} 

private String concat(String[] values) { /* trivial */} 

ContentProvider#insert 방법

public Uri insert(Uri uri, ContentValues values) { 
    SQLiteDatabase db = dbHelper.getWritableDatabase(); 
    db.beginTransaction(); 
    try { 
     // populate types 
     String[] types = ((String)values.get(Offer.TYPES)).split("|"); 
     // we no longer need it 
     values.remove(Offer.TYPES); 
     // first insert row into OFFERS 
     final long rowId = db.insert("offers", Offer.NAME, values); 
     if (rowId > 0 && types != null) { 
      // now insert all types for the row 
      for (String t : types) { 
       ContentValues type = new ContentValues(8); 
       type.put(Offer.OFFER_ID, rowId); 
       type.put(Offer.TYPE, t); 
       // insert values into second table 
       db.insert("types", Offer.TYPE, type); 
      } 
     } 
     db.setTransactionSuccessful(); 
     return ContentUris.withAppendedId(Offer.CONTENT_URI, rowId); 
    } catch (Exception e) { 
     Log.e(TAG, "Failed to insert record", e); 
    } finally { 
     db.endTransaction(); 
    } 

} 
+0

그래, 나도 같은 문제가 ... 하나의 트랜잭션에 여러 삽입 봉투하는 방법? 나는 두 개의 특별한 URI를 추가하여 이것을 관리했다 : 하나는 변환의 시작을위한 것이고 다른 하나는 끝을위한 것이다. 나는 이것이 최선의 해결책이 아니라는 것을 알고있다. 당신이 더 좋은 사람이라면 나는 그것을 감사 할 것입니다! – Bhiefer

답변

5

난 당신이 일대 다 관계의 잘못된 끝에 찾고 생각의 버전 몸매는 여전합니다.

예를 들어 ContactsContract 콘텐츠 제공 업체를 살펴보십시오. 연락처는 많은 이메일 주소, 많은 전화 번호 등을 가질 수 있습니다. 수행되는 방법은 "many"쪽에 삽입/업데이트/삭제를 수행하는 것입니다. 새 전화 번호를 추가하려면 전화 번호와 관련된 연락처의 ID를 제공하여 새 전화 번호를 삽입하십시오.

콘텐츠 공급자가없는 일반 SQLite 데이터베이스가있는 경우에도 마찬가지입니다. 관계형 데이터베이스의 일대 다 관계는 "많은"측면에 대한 테이블의 삽입/업데이트/삭제를 통해 이루어지며, 각각 "하나"면에 외래 키가 있습니다.

이제 OO 관점에서 보면 이상적인 것은 아닙니다. 당신은 하나의 측면에서 자식 콜렉션을 조작 할 수있는 ORM 스타일 래퍼 객체 (Hibernate를 생각해 보라)를 만들 수있다. 그런 다음 충분히 지능적인 콜렉션 클래스가 돌아 서서 "많은"테이블을 동기화하여 일치시킬 수 있습니다. 그러나 이것들은 적절하게 구현하는 것이 사소한 것은 아닙니다.

+0

음, 나는 하나의 메인 레코드를 가지고 있는데, 많은 전화 번호를 지칭하는 사람을 말한다. 그래서 Person 레코드를 삽입하고 키를 얻은 다음 각각의 레코드를 Person 외래 키로 제공하는 Phone 테이블에 많은 양의 레코드를 삽입합니다. 꽤 표준적인 것들. 그렇다면 두 개의 모델 객체와 Person 객체의 Phones 컬렉션과 함께 Java 측에서이 관계를 나타내는 데 아무런 문제가 없습니다. 내가 힘든 시간을 보내려면 Provider API에 이들을 연결해야합니다. ContactsContract를 공부하겠습니다. 힌트를 보내 주셔서 감사합니다. – Bostone

+0

사실 인서트는 동적이지 않습니다. 기본적으로 XML을 구문 분석하고 레코드를 삽입합니다. 일단 거기에서 나는 더 이상의 조작없이 이것들을 읽을 것이다. 나는 테이블 당 하나의 ContentResolver를 사용할 수 있다고 가정하지만 ContentProvider로서이 기능을 드러내고 싶습니다. 그리고 다시 힘든 시간을 보냅니다. – Bostone

+0

실제로 연락처 클래스를 1.5로 통과 할 것입니다 - 팁을 주셔서 다시 한번 감사드립니다. 정확히 내가 무엇을 필요로하는지 – Bostone

4

그래서 내 자신의 질문에 대답 할 것입니다. 나는 2 개의 테이블과 2 개의 모델 객체를 가지고 올바른 길을 가고있었습니다. 누락 된 부분과 나를 혼란스럽게 한 것은 ContentProvider#insert을 통해 복잡한 데이터를 직접 호출하고 싶다는 것이 었습니다. 이것은 잘못된 것입니다. ContentProvider이 두 테이블을 작성하고 유지해야하지만 사용할 테이블은 Uri 매개 변수 ContentProvider#insert에 의해 결정되어야합니다. ContentResolver를 사용하고 "addFoo"와 같은 메소드를 모델 객체에 추가하는 것이 매우 편리합니다.이러한 방법은 컨텐트 리졸버 파라미터를 가지고 끝에 여기 복소 레코드 삽입하는 순서이다 것이다 : 상위 ID (foregn 키) 및 사용을 제공 ContentProvider#insert 통해

  1. 삽입 상위 기록하고 각 하위 단위 레코드 ID
  2. 을 구하는 ContentProvider#insert 다른 Uri가 하위 레코드를 삽입하는 경우

그래서 남은 질문은 트랜잭션에서 위의 코드를 봉투하는 방법입니다.

5

ContentProviderOperations을 사용할 수 있습니다.

이들은 기본적으로 상위 행에 대해 생성 된 식별자를 역 참조 할 수있는 대량 작업입니다. ContentProviderOperations이 일대 디자인에 사용할 수있는 방법

아주 잘이 답변에 설명되어 있습니다 : What are the semantics of withValueBackReference?