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

p.s*_*eef 2 mongodb spring-data-rest spring-data-mongodb spring-boot

我正在尝试使用RepositoryRestResource和实现一个rest apiRestTemplate

除了加载@DBRef 之外,一切都运行良好

考虑这个数据模型:

public class Order
{
   @Id
   String id;

   @DBRef
   Customer customer;

   ... other stuff
}

public class Customer
{
    @Id
    String id;

    String name;

    ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

其余 api 返回以下 JSON:

{
  "id" : 4,
  **other stuff**,
  "_links" : {
    "self" : {
      "href" : "http://localhost:12345/api/orders/4"
    },
    "customer" : {
      "href" : "http://localhost:12345/api/orders/4/customer"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Ser*_*kov 6

在这种情况下急切地解决依赖实体很可能会引发N+1 数据库访问问题。我认为没有办法使用默认的 Spring Data 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 {
        ...
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. customerService.getById 可以使用缓存(例如使用 Spring @Cachable 注释)来减轻为每个结果集记录额外访问数据库的性能损失。

  4. 为您的数据模型添加冗余,并在创建/更新时将 Customer 对象字段的副本存储在 Order 集合中。

在我看来,出现这种问题是因为 MongoDB 不支持连接不同的文档集合(它的“$lookup”运算符与常见的 SQL JOIN 相比有很大的局限性)。 MongoDB 文档也不建议使用 @DBRef 字段,除非加入托管在不同服务器中的集合:

除非您有令人信服的理由使用 DBRef,否则请改用手动引用。

这里还有一个类似的问题


归档时间:

查看次数:

2090 次

最近记录:

9 年,3 月 前