@Emmanuel Bernard I guess you mentioned about my second topic; 2. Fix in multiLoad bugs with non flushed entities both side of sessionCheckingEnable true and false I agree with you partially. delete (or save) before multiLoad is not a common use case in same method. But I'm not sure never exists these kind of code. I think production code (as you said realistic code) could be possible in the same long process session such as using OSIV (Open Session In View). Some of complexity business logics call many method in the same Transaction(Session) and each method might be responsible for their operations. Then each method doesn't know entity(matched id) is deleted ( or flushed ). Below are simple examples 1. save before multiLoad in the same session
@Test
public void test() {
Session session = openSession();
session.getTransaction().begin();
List<String> requestParams = Arrays.asList("Post 1", "Post 2", "Too Long Text Post");
List<Integer> ids = createPosts(requestParams);
doSomethingIfExists(ids);
session.getTransaction().commit();
session.close();
}
public List<Integer> createPosts(List<String> texts) {
Session session = getSession();
List<Integer> createdIds = new ArrayList<>();
for (int i = 0; i < texts.size(); i++) {
Post post = new Post(texts.get(i));
session.save(post);
createdIds.add(post.getId());
}
return createdIds;
}
public void doSomethingIfExists(List<Integer> ids) {
Session session = getSession();
List<Post> posts = session.byMultipleIds(Post.class).enableSessionCheck(false).multiLoad(ids);
for (Post post : posts) {
System.out.println(post.getText());
}
}
doSomethingIfExists will print nothing; results posts is empty (session.byMultipleIds(Post.class).enableSessionCheck(false).multiLoad(ids)
public void doSomethingIfExists(List<Integer> ids) {
Session session = getSession();
List<Post> posts = session.byMultipleIds(Post.class).enableSessionCheck(true).multiLoad(ids);
for (Post post : posts) {
System.out.println(post.getText());
}
}
doSomethingIfExists will print Post 1, Post 2, Too Long Text Post (session.byMultipleIds(Post.class).enableSessionCheck(true).multiLoad(ids)
public void doSomethingIfExists(List<Integer> ids) {
Session session = getSession();
Query<Post> query = session.createQuery("from Post p where p.id in (:ids)");
query.setParameterList("ids", ids);
List<Post> posts = query.list();
for (Post post : posts) {
System.out.println(post.getText());
}
}
doSomethingIfExists will print Post 1, Post 2, Too Long Text Post (Session will flush saved posts before executing HQL query)
public void doSomethingIfExists(List<Integer> ids) {
Session session = getSession();
List<Post> posts = new ArrayList<>();
for(Integer id : ids) {
Post post = session.byId(Post.class).load(id);
posts.add(post);
}
for (Post post : posts) {
System.out.println(post.getText());
}
}
doSomethingIfExists will print Post 1, Post 2, Too Long Text Post (byId.load each Id) Only one case is different (multiLoad with sessionCheckingEnabled == false) I think Session should flush before executing multiLoad if sessionCheckingEnabled is false like executing HQL for consistency result. 2. delete before multiLoad in the same session
@Test
public void test2() {
Session session = openSession();
session.getTransaction().begin();
List<Integer> requestParams = Arrays.asList(1, 2, 3);
deleteTooLongTextPosts(requestParams);
doSomethingIfExists(requestParams);
session.getTransaction().commit();
session.close();
}
public void deleteTooLongTextPosts(List<Integer> ids) {
Session session = getSession();
Query<Post> query = session.createQuery("from Post p where p.text.size > 10 and p.id in (:ids)");
query.setParameter("ids", ids);
List<Post> posts = query.list();
for(Post post : posts) {
session.remove(post);
}
}
public void doSomethingIfExists(List<Integer> ids) {
Session session = getSession();
List<Post> posts = session.byMultipleIds(Post.class).enableSessionCheck(false).multiLoad(ids);
for (Post post : posts) {
System.out.println(post.getText());
}
}
doSomethingIfExists will print Post 1, Post 2, Too Long Text Post ; Too Long Text Post entity is already deleted in deleteTooLongTextPosts method but printed. (session.byMultipleIds(Post.class).enableSessionCheck(false).multiLoad(ids)
public void doSomethingIfExists(List<Integer> ids) {
Session session = getSession();
List<Post> posts = session.byMultipleIds(Post.class).enableSessionCheck(true).multiLoad(ids);
for (Post post : posts) {
System.out.println(post.getText());
}
}
doSomethingIfExists will print Post 1, Post 2, Too Long Text Post ; Too Long Text Post entity is already deleted in deleteTooLongTextPosts method but printed. (session.byMultipleIds(Post.class).enableSessionCheck(true).multiLoad(ids)
public void doSomethingIfExists(List<Integer> ids) {
Session session = getSession();
Query<Post> query = session.createQuery("from Post p where p.id in (:ids)");
query.setParameterList("ids", ids);
List<Post> posts = query.list();
for (Post post : posts) {
System.out.println(post.getText());
}
}
doSomethingIfExists will print Post 1, Post 2 (Session will flush saved posts before executing HQL query)
public void doSomethingIfExists(List<Integer> ids) {
Session session = getSession();
List<Post> posts = new ArrayList<>();
for(Integer id : ids) {
Post post = session.byId(Post.class).load(id);
posts.add(post);
}
for (Post post : posts) {
System.out.println(post.getText());
}
}
doSomethingIfExists will print Post 1, Post 2 (byId.load each Id) When using multiLoad printed already deleted entity. I think Session should check if managed entities are DELETED marked and exclude it. (sessionCheckingEnabled == true) If sessionCheckingEnabled == false Session should flush before executing multiLoad like HQL. I think we need to fix theses behavior for consistency result when using multiLoad. Thanks. |