Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于模型的多对多更新问题 #1519

Open
kkqy opened this issue Nov 2, 2020 · 3 comments
Open

关于模型的多对多更新问题 #1519

kkqy opened this issue Nov 2, 2020 · 3 comments

Comments

@kkqy
Copy link

kkqy commented Nov 2, 2020

module.exports = class extends think.Model {
  get relation() {
    return {
      script_tag: {
        type: think.Model.MANY_TO_MANY,
        rModel: 'script_tag_relation'
      }
  }
};

上面这个模型有个多对多关联,一个Script可以有多个Tag,多个Script可以有同一个Tag。
我使用
scriptModel.where({id:1}).update({script_tag:[1,2]});
可以自动更新关联表,让ID为1的Script和ID为1以及2的Tag关联。
但是使用
scriptModel.where({id:1}).update({script_tag:[]});
却不能删除ID为1的Script的Tag。貌似更新语句直接忽略了空数组了。
这是BUG吗?

@kkqy
Copy link
Author

kkqy commented Nov 3, 2020

我在think-model模块里
找到了relation/relation.js里的getRelationInstance方法

getRelationInstance(relationKey, data, type) {
    let item = this.relation[relationKey];
    if (!helper.isObject(item)) {
      item = { type: item };
    }
    const opts = Object.assign({
      name: relationKey,
      key: this.model.pk,
      model: relationKey,
      fKey: `${this.model.modelName}_id`,
      relation: true,
      type: Relation.HAS_ONE
    }, item);
    // relation data is exist
    if (!type) {
      // get relation data
      const itemData = helper.isArray(data) ? data[0] : data;
      const relData = itemData[opts.name];
      if (helper.isArray(relData) || helper.isObject(relData)) {
        return;
      }
    } else {
      // set relation data
      if (type !== 'DELETE' && helper.isEmpty(data[opts.name])) {
        return;
      }
    }

    const model = this.model.model(opts.model);
    // make model use the same connection when invoked in transactions
    model.db(this.model.db());

    allowOptions.forEach(allowItem => {
      let itemFn = opts[allowItem];
      if (helper.isFunction(itemFn)) {
        itemFn = itemFn.call(model, model, this.model);
      }
      if (itemFn !== undefined) {
        model[allowItem](itemFn);
      }
    });
    // disable relation in sub class
    if (opts.relation !== undefined) {
      model.setRelation(opts.relation, false);
    }
    opts.model = model;
    let Cls = null;
    switch (opts.type) {
      case Relation.HAS_MANY:
        Cls = HasMany;
        break;
      case Relation.BELONG_TO:
        // change the default key & fKey
        opts.key = item.key || `${opts.model.modelName}_id`;
        opts.fKey = item.fKey || 'id';
        Cls = BelongTo;
        break;
      case Relation.MANY_TO_MANY:
        Cls = ManyToMany;
        break;
      default:
        Cls = HasOne;
        break;
    };
    return new Cls(data, opts, this.model);
  }

问题就在

if (type !== 'DELETE' && helper.isEmpty(data[opts.name])) {
        return;
      }

如果是空数组,这里就直接返回undefined了,造成没有触发关联更新。
我修改为了

if (type !== 'DELETE' && helper.isEmpty(data[opts.name]) && !helper.isArray(data[opts.name])) {
        return;
      }

也就是把空数组排除在外,然后就正常了,但是我不知道有没有“后遗症”,所以希望项目组的看一下,这个怎么修改比较好。

@welefen
Copy link
Member

welefen commented Nov 3, 2020

你这个用 delete 应该更合适

@kkqy
Copy link
Author

kkqy commented Nov 3, 2020

你这个用 delete 应该更合适

现在是这样,前端可以编辑这个标签,传到后端直接就是ID数组,
文档里貌似没写如何增删改关联,只介绍了关联查询,update关联名称能直接修改关联,是我自己摸索出来的,文档里也没有写,增删改关联有具体说明吗?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants