【问题标题】:How to mapping an entity to multiple mongodb collection in Spring Data MongoDB with JPA without use MongoTempalte directly?如何在不直接使用 MongoTempalte 的情况下使用 JPA 将实体映射到 Spring Data MongoDB 中的多个 mongodb 集合?
【发布时间】:2021-11-12 01:29:28
【问题描述】:

我正在使用 org.mongodb:bson:4.1.2org.springframework.boot:spring-boot-starter-data-mongodb:2.4.7

我的实体看起来像:

@Entity
@Table(name = "fire_alert")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Document(collection = "alert_<dynamic>")
@Data
public class AlertPO implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "owner_id")
    private Long ownerId;

    @Column(name = "alert_type")
    private Long alertType;
}

因为会有数百万的alert,所以我需要根据AlertPO.alertType将记录保存到不同的mongodb集合中。

深入org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity后发现@Document的注解字段collection支持SpEL表达式。这种表达式会在org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity#getCollection中求值,显然当前实体不会被添加到EvaluationContext中。

根据这个问题:

How to Map a Java Entity to Multiple MongoDB Collections in Spring Data?

我们可以覆盖存储库以使用MongoTemplate 以编程方式将数据持久化到适当的集合中。但是我们将使用 JPA,我们不想直接使用MongoTemplate。如何做到这一点?

【问题讨论】:

    标签: java spring mongodb spring-boot


    【解决方案1】:

    虽然SpEL表达式的EvaluationContext不包含AlertPO的实例,但我们可以通过在BeanFactory中注册的ThreadLocal实例使其成为可能。

    如:

    @Component(value = "collection")
    public class CollectionHolder {
        private static final ThreadLocal<Stack<String>> COLLECTION = ThreadLocal.withInitial(Stack::new);
    
        public void push(Alert alert) {
            COLLECTION.get().push(typeToCollection(alert.getAlertType()));
        }
    
        public void push(Long type) {
            COLLECTION.get().push(typeToCollection(type));
        }
    
        public String top() {
            return COLLECTION.get().peek();
        }
    
        public void pop() {
            COLLECTION.get().pop();
        }
    }
    

    现在我们可以推送集合名称了:

    @Service
    public class MongoAlertStorage implements IAlertStorage {
        @Autowired
        private CollectionHolder holder;
        @Autowired
        private AlertRepository alertRepository;
        @Autowired
        private Converters converters;
    
        @Override
        public Alert save(Alert alert) throws Exception {
            try {
                holder.push(alert);
                return converters.of(alertRepository.save(converters.of(alert)));
            } finally {
                holder.pop();
            }
        }
    }
    

    是时候在表达式中指定动态集合了:

    @Document(collection = "alert_#{@collection.top()}")
    public class AlertPO implements Serializable {
        // ...
    }
    

    现在,您可以在org.springframework.expression.common.CompositeStringExpression#getValue(org.springframework.expression.EvaluationContext) 进行调试以检查评估的值,它应该是您想要的。

    【讨论】:

      猜你喜欢
      • 2019-02-16
      • 2015-10-31
      • 1970-01-01
      • 1970-01-01
      • 2020-02-21
      • 2011-10-10
      • 2016-12-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多