You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ObjectBox中User与Location多对多关系删除失效及更新方法咨询

问题:ObjectBox多对多关系删除失效,需明确操作逻辑

我有User和Location两个实体,二者是多对多(Many-to-Many)关联,关系创建功能正常,但删除关系时失效。需求是仅删除实体间的关系,而非删除实体本身。

想问:删除关系需要在两个实体上都操作吗?还是仅需在带有@Backlink注解的实体上操作?

我尝试了多种基于.remove() + .put()的解决方案,但均未成功。实体定义如下:

@Entity()
class LocationModel {
  @Id()
  int localId = 0;

  @Unique(onConflict: ConflictStrategy.replace)
  int id;

  @Backlink('location')
  final items = ToMany<ItemModel>();

  final users = ToMany<UserModel>();
}


@Entity()
class UserModel {
  @Id()
  int localId = 0;

  @Unique(onConflict: ConflictStrategy.replace)
  String guid;

  @Backlink('user')
  final items = ToMany<ItemModel>();

  @Backlink()
  final locations = ToMany<LocationModel>();
}

现有一个用于更新Location与User关系的方法,传入Location实体和API返回的该Location关联用户列表,目标是仅更新两者间的关系。后续也计划在User集合中实现类似方法,传入User实体和关联Location列表进行更新。当前方法实现如下:

LocationModel updateUsers(
   LocationModel locationModel, 
   List<UserModel> users,
 ) {
    // Update users that may still have a link to this location
    final usersByLocation = userCollection.getByLocation(locationModel.localId);

    // Remove relationship with location if no users (users.isEmpty) or no longer present in users list
    final userToRemoveLocation = users.isEmpty
        ? usersByLocation
        : usersByLocation
            .where((user) => !users.any((u) => u.guid == user.guid))
            .toList();

    for (var user in userToRemoveLocation) {
      user.locations.remove(locationModel);
      userCollection.put(user);

      final locationInDb = locationBox.get(locationModel.localId);
      if (locationInDb != null) {
        locationInDb.users.remove(user);
        locationBox.put(locationInDb);
      }
    }

    // Creation of new relationships between location and users (users list)
    for (var user in users) {
      final userInDb = userCollection.getByServerId(user.guid);
      if (userInDb != null) {
        userInDb.locations.add(locationModel);
        userCollection.put(userInDb);

        final locationInDb = locationBox.get(locationModel.localId);
        if (locationInDb != null) {
          locationInDb.users.add(user);
          locationBox.put(locationInDb);
        }
      }
    }

    return locationModel;
  }

回答

核心结论

在ObjectBox的多对多关系中,只需要操作其中一方的ToMany集合,ObjectBox会自动同步更新反向的Backlink关系,完全不需要两边都手动操作。你的代码里重复操作两边反而可能导致逻辑冲突,这也是删除失效的主要原因。

问题分析

看你的实体定义:

  • LocationModel里的users是主动关联的ToMany<UserModel>
  • UserModel里的locations是带@Backlink()的反向关联集合

Backlink是ObjectBox自动维护的「镜像关系」,当你修改主动关联的集合并保存后,反向的Backlink集合会自动同步更新;反过来修改Backlink集合并保存,主动关联也会同步。

简化后的正确实现

你可以简化updateUsers方法,只需要维护其中一侧的关联集合即可。下面是基于LocationModel侧的实现:

LocationModel updateUsers(
  LocationModel locationModel, 
  List<UserModel> users,
) {
  // 必须操作数据库中取出的持久化实例,避免内存对象与数据库状态不一致
  final locationInDb = locationBox.get(locationModel.localId)!;

  // 1. 筛选出需要移除的关联用户
  final targetUserGuids = users.map((u) => u.guid).toSet();
  locationInDb.users.removeWhere((user) => !targetUserGuids.contains(user.guid));

  // 2. 添加新的/未关联的用户
  for (var user in users) {
    final userInDb = userCollection.getByServerId(user.guid);
    if (userInDb != null && !locationInDb.users.contains(userInDb)) {
      locationInDb.users.add(userInDb);
    }
  }

  // 仅保存Location实例,ObjectBox会自动同步更新User的locations集合
  locationBox.put(locationInDb);

  return locationInDb;
}

额外注意事项

  • 必须操作从数据库取出的持久化实体,而非内存中的临时对象,否则修改不会被正确持久化
  • 如果选择维护UserModel侧的locations集合,逻辑完全一致:修改user.locations并保存用户,Location的users集合会自动更新
  • 禁止同时修改两边的集合,这会打乱ObjectBox的自动同步逻辑,导致关系删除或更新失效

内容的提问来源于stack exchange,提问作者giles jeremy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 12:27:24