在 Spring 数据的 RepositoryRestResource 中急切加载 MongoDB @DBRef

Eagerly load MongoDB @DBRef in Spring data's RepositoryRestResource

我正在尝试使用 RepositoryRestResourceRestTemplate

实现休息 api

除了加载@DBRef 的

外,一切都很好

考虑这个数据模型:

public class Order
{
   @Id
   String id;

   @DBRef
   Customer customer;

   ... other stuff
}

public class Customer
{
    @Id
    String id;

    String name;

    ...
}

以及以下存储库(与客户类似)

@RepositoryRestResource(excerptProjection = OrderSummary.class)
public interface OrderRestRepository extends MongoRepositor<Order,String>{}

其余apireturns以下JSON:

{
  "id" : 4,
  **other stuff**,
  "_links" : {
    "self" : {
      "href" : "http://localhost:12345/api/orders/4"
    },
    "customer" : {
      "href" : "http://localhost:12345/api/orders/4/customer"
    }
  }
}

如果由 resttemplate 正确加载,将创建一个新的 Order 实例,其中 customer = null

是否可以在存储库端热切解决客户并嵌入 JSON?

在这种情况下急切解决依赖实体很可能会引发 N+1 database access problem。 我认为没有办法使用默认 Spring 数据 REST/Mongo 存储库实现来做到这一点。

这里有一些备选方案:

  1. 构造一个自己的自定义@RestController 方法,该方法将访问数据库并构造所需的输出
  2. 使用 Projections 填充相关集合中的字段,例如

    @Projection(name = "main", types = Order.class)
    public interface OrderProjection {
        ...
    
        // either
        @Value("#{customerRepository.findById(target.customerId)}")
        Customer getCustomer();
    
        // or
        @Value("#{customerService.getById(target.customerId)}")
        Customer getCustomer();
    
        // or
        CustomerProjection getCustomer();
    } 
    
    @Projection(name = "main", types = Customer.class)
    public interface CustomerProjection {
        ...
    }
    
  3. customerService.getById 可以使用缓存(例如使用 Spring @Cachable annotation)来减轻为每个结果集记录额外访问数据库的性能损失。

  4. 向您的数据模型添加冗余,并将 Customer 对象字段的副本存储在 creation/update 上的订单集合中。

出现这种问题,在我看来,是因为MongoDB不支持很好地连接不同的文档集合(它的"$lookup" operator与常见的[=48=相比有很大的局限性]加入)。 MongoDB docs also do not recommend 使用@DBRef 字段,除非加入托管在不同服务器上的集合:

Unless you have a compelling reason to use DBRefs, use manual references instead.

这里也有类似的question