字符串集在 Spring JPA 投影接口中不正常

Set of String is not acting normal in Spring JPA Projection Interface

我正在使用投影接口 return 实体的局部视图,局部视图包含一组字符串。我希望 Set 正常工作,但它不是:当我向它添加一个新的字符串时,它会忽略该字符串,请参见下面的示例代码:

@Entity public class MyEntity {
    @Id private Long id;
    @ElementCollection private Set<String> strings;
    // more fields
    // getters and setters
}

public interface MyEntityRepo extends CrudRepository<MyEntity, Long> {
    MyEntityPartial getMyEntityPartialById(Long id);
}

public interface MyEntityPartial {
    Set<String> getStrings();
}

@DataJpaTest public class MyTest {
    @Autowired private MyEntityRepo repo;
    @BeforeEach private void setup() {
        MyEntity myEntity = new MyEntity();
        myEntity.setId(1L);
        Set<String> strings = new HashSet<>();
        strings.add("A");
        myEntity.setStrings(strings);
        repo.save(myEntity);
    }
    @Test public void exampleTest() {
        MyEntityPartial myEntityPartial = repo.getMyEntityPartialById(1L);
        assertThat(myEntityPartial, is(notNullValue()));
        assertThat(myEntityPartial.getStrings(), containsInAnyOrder("A"));
        myEntityPartial.getStrings().add("B");
        assertThat(myEntityPartial.getStrings(), containsInAnyOrder("A", "B"));
    }
}

此处测试在最后一个断言处失败,因为 myEntityPartial.getStrings() 仍然仅包含“A”,但不包含“A”和“B”。我检查了投影实例的 Set myEntityPartial 不是正常的 HashSet 而是 org.hibernate.collection.internal.PersistentSet。想知道这是否是问题所在?以及如何告诉 Hibernate 或 Spring 在投影界面中使用 HashSet

注意:我之前没有在 Spring Data JPA 中使用过投影。所以谢谢你分享这个! :直到

我认为 myEntityPartial.getStrings().add("B"); 有问题。 它不会更新 MyRepo 管理的实际 MyEntity。每次执行 myEntityPartial.getStrings() 我猜 returns 数据库中实体的最新投影。

但如果我们将 myEntityPartial.getStrings() 存储在本地集合中,它就可以工作!

@Test public void exampleTest() {
    MyEntityPartial myEntityPartial = repo.getMyEntityPartialById(1L);
    Set<String> partialSet = myEntityPartial.getStrings();
    assertNotNull(myEntityPartial);
    assertTrue(partialSet.contains("A"));
    partialSet.add("B");
    assertTrue(partialSet.contains("A"));
    assertTrue(partialSet.contains("B"));
}

我假设这不是测试的真正目的?
因此,如果由存储库管理的实体已更新,则它会起作用

 @Test public void exampleTest2() {
    MyEntityPartial myEntityPartial = repo.getMyEntityPartialById(1L);
    assertNotNull(myEntityPartial);
    assertTrue(myEntityPartial.getStrings().contains("A"));

    //update the entity in db
    updateEntity("B");
    assertTrue(myEntityPartial.getStrings().contains("A"));
    assertTrue(myEntityPartial.getStrings().contains("B"));
}

/*
 * Updating actual entity, returns B with partial projection
 */
private void updateEntity(String newStrings){
    MyEntity entity = repo.findById(1L).get();
    Set<String> existing = entity.getStrings();
    existing.add(newStrings);
    entity.setStrings(existing);
    repo.save(entity);
}

此外,myEntityPartial.getStrings() 显示了 LinkedHashSet 类型。

希望这有助于解决问题。