2016-01-21 6 views
6

मैं एक Android परियोजना पर काम कर रहा हूँ और वर्तमान में कोशिश कर रहा हूँ में वृत्तीय संदर्भ के साथ अच्छी तरह से संबंधित है यह पता लगाने की हमारी API रों है कि एक वस्तु ग्राफ में संदर्भ चक्र भी शामिल है, जो मैं कर सकते हैं से कुछ JSON deserialize करने के लिए कैसे फिर डेटाबेस में हेरफेर और स्टोर करें। मुझे एक उदाहरण देता हूँ:पार्सिंग रूपरेखा है कि JSON

{ 
    "id": "24", 
    "name": "Bob", 
    "friends": [ 
     { 
      "id": "13", 
      "name": "Alice", 
      "friends": [ 
       { 
       "id": "24" // and we have a circular reference 
       } 
      ] 
     } 
    ] 
} 

यहाँ, एक व्यक्ति वस्तु बुलाया Bob मित्र व्यक्ति Alice साथ है, और AliceBob साथ बारी मित्रों में है। चूंकि रिलेशनशिप रिकर्सिव है, Alice के दोस्तों के रिश्ते Bob को अब पूर्ण व्यक्ति ऑब्जेक्ट के रूप में नहीं समझा जाता है, लेकिन केवल id प्रदान किया जाता है।

उपरोक्त चरणों को करने के लिए आप किस टूल का उपयोग करते हैं? मैंने जैक्सन के साथ ऑब्जेक्ट मैपिंग भाग को लागू करने का प्रयास किया लेकिन चक्र आवश्यकता के लिए समाधान खोजने में विफल रहा। मुझे इस विषय के बारे में ongoing discussion मिला है जो JSOG का उल्लेख करता है जो उपयोगी हो सकता है, लेकिन हमारे एपीआई तय किए गए हैं और जेएसओजी अनुपालन नहीं करते हैं।

मूल रूप से जो मैं खोज रहा हूं वह एंड्रॉइड के लिए रेस्टकिट (आईओएस फ्रेमवर्क) जैसा कुछ है।

+0

मैं आईडी, नाम, दोस्तों को पार्स करने के लिए एक विधि बना सकता हूं और इसे आगे की प्रक्रिया के लिए सूची या किसी डेटा संरचना के रूप में वापस कर सकता हूं, क्या इससे मदद मिलेगी? –

उत्तर

4

एक बार एपीआई तय हो गई है, मैं इसे इस तरह से लागू होगी:

डीबी दृष्टिकोण से, मैं 2 टेबल होगा - UserTable और RelationsTable अपने मित्रों के सभी किनारे रखने के लिए ग्राफ़:
enter image description here

आईई विचार उपयोगकर्ताओं को एक तालिका में और संबंध तालिका में उनके संबंधों में रखना है। यह बाद में इसके ऊपर कुछ अतिरिक्त तर्क भी जोड़ने की अनुमति देता है (उदाहरण के लिए, उपयोगकर्ता अपने कनेक्शन को छुपाता है या किसी को ब्लॉक करता है, आदि - ग्राफ के किसी भी संभावित किनारों)। इसके अलावा, यह परिपत्र संदर्भ के साथ समस्याओं को कम करने की अनुमति देता है।

सेवा & पार्स जेसन से डेटा पुनर्प्राप्त करने के लिए एक ढांचे के रूप में, मैं Retrofit का उपयोग करूंगा।

पहले, मैं UserBase और User कक्षाएं निर्धारित करेंगे:

public class UserBase { 
    public string id; 
} 

public final class User extends UserBase { 
    public string name; 
    public List<UserBase> friends; 
    // user's "real" friends, not just ids, fills from SQLite 
    public List<User> userFriends; 
} 

जहां, जैसा कि आप देख सकते हैं, friendsRetrofit JSON और userFriends से वस्तु को पार्स करने के लिए UserBase वस्तुओं की एक सूची है - सूची, जिसे हम आगे चरणों में SQLite से मैन्युअल रूप से भर देंगे।

public interface Dao<TItem> { 
    void add(List<TItem> items); 
    void removeAll(); 
    List<TItem> getAll(); 
} 
.... 
public abstract class AbstractDao<TItem> implements Dao<TItem> { 
    protected final SQLiteDatabase database; 
    protected final SqlUtilities sqlUtilities; 

    public AbstractDao(SQLiteDatabase database, SqlUtilities sqlUtilities) { 
     this.database = database; 
     this.sqlUtilities = sqlUtilities; 
    } 
} 

अब हम दाव के RelatedTable के लिए और के लिए UserTable की जरूरत है::

public class UserRelation { 
    public String mainUserId; 
    public String relatedUserId; 
} 
... 
public interface UserRelationDao extends Dao<UserRelation> { 
    ... 
    List<User> getFriends(String userId); 
    ... 
} 
... 
public interface UserDao extends Dao<User> { 
    ... 
    void addWithIgnore(List<TItem> items); 
    void update(List<TItem> items); 
    void upsert(List<TItem> items); 

    User getById(String userId); 
    ... 
} 

इसके पूर्ण हो जाने, हम वास्तव में इस लागू कर सकते हैं

अब, चलो कुछ मदद वर्गों डीबीएस के साथ संचालित करने के लिए निर्दिष्ट कर सकते हैं इंटरफेस:

DefaultUserRelationDao वर्ग:

public class DefaultUserRelationDao extends AbstractDao<UserRelation> implements UserRelationDao { 
    static final String MAIN_USER_COLUMN = "mainuser"; 
    static final String RELATED_USER_COLUMN = "relateduser"; 

    private static final String[] COLUMN_NAMES = new String[]{ 
      MAIN_USER_COLUMN, 
      RELATED_USER_COLUMN, 
    }; 

    private static final String[] COLUMN_TYPES = new String[]{ 
      "TEXT", 
      "TEXT", 
    }; 

    private static final String TABLE = "userrelation"; 
    static final String CREATE_TABLE = SqlUtilities.getCreateStatement(TABLE, COLUMN_NAMES, COLUMN_TYPES); 
    static final String ALL_CONNECTED_USERS = 
      "SELECT " + Joiner.on(",").join(DefaultUserDao.COLUMN_NAMES) + 
        " FROM " + UserTable.TABLE_NAME + "," + TABLE + 
        " WHERE " + RELATED_USER_COLUMN + "=" + DefaultUserDao.USER_ID_COLUMN; 

    public DefaultUserRelationDao(SQLiteDatabase database, SqlUtilities sqlUtilities) { 
     super(database, sqlUtilities); 
    } 

    @Override 
    public void add(List<UserRelation> userRelations) { 
     try { 
      database.beginTransaction(); 
      ContentValues contentValues = new ContentValues(); 

      for (UserRelation relation : userRelations) { 
       sqlUtilities.setValuesForUsersRelation(contentValues, relation); 
       database.insertOrThrow(TABLE, null, contentValues); 
      } 

      database.setTransactionSuccessful(); 
     } finally { 
      database.endTransaction(); 
     } 
    } 

    @Override 
    public List<User> getFriends(String userId) { 
     Cursor cursor = database.rawQuery(ALL_CONNECTED_USERS, new String[]{userId}); 
     return sqlUtilities.getConnectedUsers(cursor); 
    } 
} 

और DefaultUserDao वर्ग:

public final class DefaultUserDao extends AbstractUDao<User> implements UserDao { 

    public static final String USER_ID_COLUMN = "userid"; 
    static final String USER_NAME_COLUMN = "username"; 

    public static final String[] COLUMN_NAMES = new String[]{ 
      USER_ID_COLUMN, 
      USER_NAME_COLUMN, 
    }; 

    private static final String TABLE = "users"; 
    private static final String SELECT_BY_ID = 
      SqlUtilities.getSelectWhereStatement(TABLE, COLUMN_NAMES, new String[]{ USER_ID_COLUMN }); 

    static final String CREATE_TABLE = SqlUtilities.getCreateStatement(TABLE, COLUMN_NAMES, COLUMN_TYPES); 

    public DefaultUserDao(SQLiteDatabase database, SqlUtilities sqlUtilities) { 
     super(database, sqlUtilities); 
    } 

    @Override 
    public void add(List<User> users) { 
     try { 
      database.beginTransaction(); 
      ContentValues contentValues = new ContentValues(); 

      for (User user : users) { 
       sqlUtilities.setValuesForUser(contentValues, user); 
       database.insertOrThrow(UserTable.TABLE_NAME, null, contentValues); 
      } 

      database.setTransactionSuccessful(); 
     } finally { 
      database.endTransaction(); 
     } 
    } 

    @Override 
    public User getById(String userId) { 
     return getUserBySingleColumn(SELECT_BY_ID, userId); 
    } 
    ..... 
    private User getUserBySingleColumn(String selectStatement, String value) { 
     Cursor cursor = database.rawQuery(selectStatement, new String[]{value}); 
     List<User> users = sqlUtilities.getUsers(cursor); 
     return (users.size() != 0) ? users.get(0) : null; 
    } 
} 

हमारे टेबल बनाने के लिए, हम SQLiteOpenHelper का विस्तार करने और onCreate() वास्तव में बनाने के तालिकाओं में की जरूरत है:

public final class DatabaseHelper extends SQLiteOpenHelper { 
    static final String DATABASE_NAME = "mysuper.db"; 
    public DatabaseHelper(Context context) { 
     super(context, DATABASE_NAME, null, SCHEMA_VERSION); 
    } 

    @Override 
    public void onCreate(SQLiteDatabase db) { 
     db.execSQL(DefaultUserDao.CREATE_TABLE); 
     db.execSQL(DefaultUserRelationDao.CREATE_TABLE); 
    } 
    ... 
} 

अब, मैं सभी के साथ LocalStorage इंटरफेस को परिभाषित करने के सुझाव देंगे कैश के साथ संभावित क्रियाएं:

  • सभी उपयोगकर्ता
  • प्राप्त करें प्रयोक्ता आईडी द्वारा
  • प्राप्त
  • उपयोगकर्ताओं
  • उपयोगकर्ताओं के बीच संबंध आदि

    public interface LocalStorage { 
        User getUserById(String userId); 
        void addUsers(List<User> users); 
        .... 
    } 
    

जोड़ने जोड़ सकते हैं और यह कार्यान्वयन है:

public final class SqlLocalStorage implements LocalStorage { 

    private UserDao userDao; 
    private UserRelationDao userRelationDao; 

    private SQLiteDatabase database; 
    private final Object initializeLock = new Object(); 
    private volatile boolean isInitialized = false; 
    private SqlUtilities sqlUtilities; 

    // there database is 
    // SQLiteOpenHelper helper = new DatabaseHelper(context); 
    // database = helper.getWritableDatabase(); 
    public SqlLocalStorage(SQLiteDatabase database, SqlUtilities sqlUtilities) { 
     this.database = database; 
     this.sqlUtilities = sqlUtilities; 
    } 

    @Override 
    public User getUserById(String userId) { 
     initialize(); 

     User user = userDao.getById(userId); 
     if (user == null) { 
      return null; 
     } 

     List<User> relatedUsers = userRelationDao.getFriends(userId); 
     user.userFriends = relaterUsers; 
     return user; 
    } 

    @Override 
    public void addUsers(List<User> users) { 
     initialize(); 

     for (User user : users) { 
      for (UserBase friend : user) { 
       UserRelation userRelation = new UserRelation(); 
       userRelation.mainUserId = user.id; 
       userRelation.relatedUserId = friend.id; 

       UserRelation userRelationMutual = new UserRelation(); 
       userRelationMutual.mainUserId = friend.id; 
       userRelationMutual.relatedUserId = user.id; 

       userRelationDao.add(userRelation); 
       userRelationMutual.add(userRelation) 
      } 
     } 

     userDao.addWithIgnore(users); 
    } 

    void initialize() { 
     if (isInitialized) { 
      return; 
     } 

     synchronized (initializeLock) { 
      if (isInitialized) { 
       return; 
      } 

      Log.d(LOG_TAG, "Opens database"); 
      userDao = new DefaultUserDao(database, sqlUtilities); 
      userRelationDao = new DefaultUserRelationDao(database, sqlUtilities); 
      isInitialized = true; 
     } 
    } 
} 

अंतिम चरण - वास्तविक इसका उपयोग:

//somewhere in non-UI thread 
List<User> users = dataSource.getUsers(); 
localStorage.addUsers(users); 
final User userBob = localStorage.getUserById("42"); 

एनबी! मैं यहां अपने कस्टम वर्ग एसक्यूएलटीटी का उपयोग कर रहा हूं। दुर्भाग्य से, यह इसे यहाँ पोस्ट करने के लिए जिस तरह से बहुत बड़ा है, लेकिन सिर्फ एक उदाहरण कुछ विचार अंदर क्या है देने के लिए - यहाँ कैसे getUsers (कर्सर कर्सर) वहाँ दिखाई देता है:

..... 
public List<User> getUsers(Cursor cursor) { 
    ArrayList<User> users = new ArrayList<>(); 
    try { 
     while (cursor.moveToNext()) { 
      users.add(getUser(cursor)); 
     } 
    } finally { 
     cursor.close(); 
    } 

    return users; 
} 

private User getUser(Cursor cursor) { 
    User user = new User(cursor.getString(0)); 
    user.FullName = cursor.getString(1); 
    .... 
    return user; 
} 
..... 

मुझे आशा है कि, क्या आप मुझे कुछ लंघन माफ कर देंगे विवरण (विशेष रूप से, मामले के संबंध में, जब डीबी को अद्यतन किया जाना है, जब डेटा पूर्ण नहीं होता है और इसे कैश से प्राप्त करने के अलावा, आपको इसे पहले सर्वर से पुनर्प्राप्त करना होगा, और फिर उसे कैश में लोड करना होगा)। यदि कोई महत्वपूर्ण हिस्सा गुम है - कृपया इसे टिप्पणियों में पोस्ट करें और मुझे पोस्ट अपडेट करने में खुशी होगी।

मुझे उम्मीद है कि यह आपकी मदद करेगा।

+1

प्रतिक्रिया के लिए धन्यवाद, आपके विचारों ने बहुत पहले से ही मदद की है! हालांकि, आपका उत्तर मेरे प्रश्न के विश्लेषण भाग को छोड़ देता है, जेएसओएन (ढांचे या कस्टम कोड का उपयोग करके) में चक्रों को कैसे संभालना है, यही वह है जो मुझे सबसे ज्यादा रूचि है। कोई विचार? – RaffAl

+2

@Bearwithme वास्तव में, यह नहीं है :-) Retrofit अपने JSON को स्वयं ही पार करता है। बस अपने 'उपयोगकर्ता' के गुणों को रखें, जिन्हें आप 'सार्वजनिक' और जेएसओएन में समान नामों के साथ पार्स किया जाना चाहते हैं, और ढांचा स्वचालित रूप से अपना काम करेगा –

+2

यानी जैसा कि आप देख सकते हैं, मैं मित्र की सूची को सूची के रूप में पार्स कर रहा हूं 'UserBase' क्लास ऑब्जेक्ट्स (आईडी) के, और रिकर्सन –

0

मैं कहूंगा कि आप गलत समस्या को हल करने का प्रयास कर रहे हैं & वास्तविक समस्या यह है कि आपका डेटा प्रतिनिधित्व टूट गया है। साथ ही परिपत्र रेफरी समस्या भी अक्षम है जिसमें प्रत्येक मित्र को दोस्ती के लिए डुप्लीकेट किया जाता है। एक HashMap<Integer, Person> (या SparseArray<Person>) में सूची

[ 
    { 
     "id": "13", 
     "name": "Alice", 
     "friends": ["24"] 
    }, 
    { 
     "id": "24", 
     "name": "Bob", 
     "friends": ["13"] 
    } 
] 

स्टोर: बेहतर इस तरह उन लोगों की सूची समतल। काम हो गया!

+0

आपकी प्रतिक्रिया के लिए धन्यवाद! हालांकि, मुझे डर है कि आपने मेरे प्रश्न को गलत समझा। मुझे उम्मीद थी कि मैं इसे स्पष्ट कर रहा था। जैसा कि आप देख सकते हैं कि हमारा एपीआई प्रस्ताव अनिश्चित काल तक पूर्ण वस्तु वापस नहीं करता है। जब ऑब्जेक्ट प्रतिक्रिया में पहले ही दिखाई दे रहा है तो केवल उसकी आईडी लौटा दी जाती है। हालांकि, मैं जो मांग रहा हूं वह ढांचे के लिए सुझाव है जो ऐसी चीजों को पार्स करने में सक्षम हैं, सही ढंग से संबंध स्थापित कर रहे हैं। – RaffAl

+0

ठीक है लेकिन आपकी एपीआई अभी भी समस्या है। आपको इसके बारे में भी सोचने की ज़रूरत नहीं है, बस अपने मॉडल में परिपत्र रेफरी से बचें। –

+1

मैं असहमत हूं। मॉडल द्वारा परिपत्र में परिपत्र रेफरी से बचने से निपटने का एक ही तरीका है। अच्छा उदाहरण इस मामले में जेएसओजी मानक है, वहां संरचना फ्लैट नहीं है, परिपत्र संदर्भ होता है, और लगभग उसी तरह वर्णित किया गया है जिस तरह से मैंने अपना उदाहरण जेएसओएन बनाया है। – RaffAl

1

आप JSON-RPC पर एक नज़र डाल सकते हैं। यह एक अच्छा ढांचा है जो जटिल ऑब्जेक्ट रिलेशनशिप के जेएसओएन पार्सिंग और ऑब्जेक्ट मैपिंग का समर्थन करता है।

+0

उत्तर के लिए धन्यवाद, यह जांच लेंगे! – RaffAl

संबंधित मुद्दे