表A、表B同时有一个属性(pointer)指向对方时失败


参加学校的举办的移动应用大赛时,需要用到数据库,偶然看到leanCloud,觉得非常好,就将其放进了项目中。但这两天却因为表的结构遇到了一点问题,下面是项目中涉及到问题的两张表的设计,User表中有一个**restaurant**字段是**pointer类型**,指向的Restaurant表,同样Restaurant表中有一个字段**shopkeeper**也是**pointer类型**,指向User表。


之所以这样设计,是因为这次开发的应用(一个类似于外卖app的应用),我们小组将原本的商家版和用户版合二为一,转而用User的userType属性决定顾客和店主(shopkeeper)进入应用时局部功能的不同。所以我们将User和Restaurant表进行了划分和联系。店主登录时,可以管理自己的店铺,故而User表中有一个属性指向Restaurant(顾客在该字段上为空),这样免于在Restaurant表执行find操作,确定该店主的餐馆。而平时顾客浏览店铺时可以很快的从Restaurant的shopkeeper字段上获取店主的信息(比如联系方式),也免于find操作。
但这时候问题就出现了,当店主添加店铺信息成功后,进行店主与餐馆的双向绑定时(即店主的restaurant字段指向刚创建好的餐馆,同时把餐馆的shopkeeper字段指向该店主)出现了错误,只进行了一半就报错,查表发现店主的restaurant字段已经是该餐馆,但是餐馆的shopkeeper字段为空,试了多次无果。以下是报错信息

09-18 09:55:01.619 16489-16489/? E/AndroidRuntime:     at com.alibaba.fastjson.serializer.MapSerializer.write(MapSerializer.java:248)
                                                       at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:275)
                                                       at com.alibaba.fastjson.JSON.toJSONString(JSON.java:648)
                                                       at com.alibaba.fastjson.JSON.toJSONString(JSON.java:586)
                                                       at com.avos.avoscloud.AVObjectSerializer.write(AVObjectSerializer.java:60)
                                                       at com.alibaba.fastjson.serializer.MapSerializer.write(MapSerializer.java:248)
                                                       at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:275)
                                                       at com.alibaba.fastjson.serializer.MapSerializer.write(MapSerializer.java:248)

09-18 09:55:02.030 16489-16489/? E/AndroidRuntime: Error reporting crash
                                                   android.os.TransactionTooLargeException: data parcel size 6432400 bytes
                                                       at android.os.BinderProxy.transactNative(Native Method)
                                                       at android.os.BinderProxy.transact(Binder.java:615)
                                                       at android.app.ActivityManagerProxy.handleApplicationCrash(ActivityManagerNative.java:5103)
                                                       at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:97)
                                                       at com.avos.avoscloud.AVUncaughtExceptionHandler.endApplication(AVUncaughtExceptionHandler.java:160)
                                                       at com.avos.avoscloud.AVUncaughtExceptionHandler.handleException(AVUncaughtExceptionHandler.java:102)
                                                       at com.avos.avoscloud.AVUncaughtExceptionHandler.uncaughtException(AVUncaughtExceptionHandler.java:55)
                                                       at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1068)
                                                       at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1063)

09-18 09:58:15.683 19085-19085/? E/AndroidRuntime:     at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)
                                                       at com.avos.avoscloud.AVObject.processOperationData(AVObject.java:1829)

寻求多方解无果,最后只得委曲求全将User表的restaurant字段该为restaurantId,类型改为String,作用任然是存储对应的Restaurant的ObjectID,问题解决,但是还是很疑惑为什么会出现这个问题,后来自己写了个小demo,再次验证还是出现这样的问题。


public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TestA mTestA;
private TestB mTestB;

private static final String TAG = "MainActivity";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button btnNewA = (Button) findViewById(R.id.btn_new_a);
    btnNewA.setOnClickListener(this);
    Button btnNewB = (Button) findViewById(R.id.btn_new_b);
    btnNewB.setOnClickListener(this);
    Button btnApointB = (Button) findViewById(R.id.btn_a_point_b);
    btnApointB.setOnClickListener(this);
    Button btnBpointA = (Button) findViewById(R.id.btn_b_point_a);
    btnBpointA.setOnClickListener(this);
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btn_new_a:
            mTestA = new TestA();
            Log.d(TAG, "onClick: " + mTestA.toString());
            break;
        case R.id.btn_new_b:
            mTestB = new TestB();
            Log.d(TAG, "onClick: " + mTestB.toString());
            break;
        case R.id.btn_a_point_b:
            mTestA.setPointB(mTestB);
            mTestA.saveInBackground();
            Log.d(TAG, "onClick: " + mTestA.toString());
            break;
        case R.id.btn_b_point_a:
            mTestB.setPointA(mTestA);
            mTestB.saveInBackground();
            Log.d(TAG, "onClick: " + mTestB.toString());
            break;
    }
}
}



测试多次,TestA对象能指向TestB,但是TestB不能指向TestA,也就是不能同时出现A->B,B->A。现在想问问大牛们是为什么,是leanCloud不支持,还是我这样是不符合规范的?

如果 User 已经存在,那么这样保存理应是可以的。 @daweibayu

但是实际测试时并不行,第三个异常直接导致程序退出,想问问具体原因是什么

您好,可以把 demo 私信发给我吗?点我头像发私信。我来调查一下。

你这里的问题是 AVObject 的引用变了,应该在 callback 回调里拿到 AVObject 保存成功后的 objectId。

在 MainActivity 改动 2 处代码:
1、 声明 2 个 String

  String aID;
  String bID;

2、click 点击事件里

      case R.id.btn_a_point_b:
        mTestA.setPointB(mTestB);
        mTestA.saveInBackground(new SaveCallback() {
          @Override
          public void done(AVException e) {
            aID = mTestA.getObjectId();
            bID = mTestB.getObjectId();
          }
        });
        Log.d(TAG, "onClick: " + mTestA.toString());
        break;
      case R.id.btn_b_point_a:
        AVObject.createWithoutData("TestB", bID).put("pointB", AVObject.createWithoutData("TestA", aID));
        mTestB.saveInBackground();
        Log.d(TAG, "onClick: " + mTestB.toString());
        break;