New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue of Repository output sql [DATAJPA-942] #1293
Comments
Oliver Drotbohm commented SQL generation is handled by your persistence provider which I assume is Hibernate in this case. Did you already check with them? |
Ben Li commented hi, good to hear your reply. Our persistence provider is Hibernate, and we have checked and confirmed that SQL generation is fine. But the issue occurred as my description. We have no idea about that, any suggestion? Thanks!! |
Oliver Drotbohm commented Call me puzzled. Your original description states that you expect other SQL generated. Now you say SQL generation is fine. If the latter is the case, then what is the ticket about? |
Frank Tang commented SQL generation fine means following situation:
this will generate the right sql when add an expicit |
Ben Li commented yes, SQL generation fine means: although the sql generated, not as my expectation. Such as: wrong sql generation: my expectation |
Oliver Drotbohm commented I can't reproduce your claims on an example. From the Spring Data JPA test cases:
A manually defined query
That just generates the SQL you mentioned to be improvable, but it looks like that's just what Hibernate generates |
Frank Tang commented Your provided test case is not the same as ours in the demo attachment.In our demo,following 2 points must be noticed: We defined a method in repository B like: this method makes association C which extends from a MappedSuperclass as a where condition. When add an annotation In our product, entity A is a base entity, and many repositories contain many method names make C as a filter query condition.As db data grows,this wrong sql will give a bad impact on performance.. |
Oliver Drotbohm commented The point it, it doesn't make any difference. I've adapted my test case to use your domain types and I still get: select b0_.id as id1_0_, b0_.c_id as c_id3_0_, b0_.name as name2_0_ from b b0_ left outer join c c1_ on b0_.c_id=c1_.id where c1_.id=? and b0_.name=? The manually declared query My point is: there's no way for us to use the Criteria API in any other way, if we define the join explicitly as it's not under our control how HIbernate translates that criteria API setup into an actual query. And as you can see it doesn't make any difference whether there's inheritance involved or the like. Here's the test case I used: @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DemoApplication.class)
public class FooTest {
@PersistenceContext EntityManager em;
@Test
public void buildQueryUsingCriteriaApi() {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<B> query = builder.createQuery(B.class);
Root<B> root = query.from(B.class);
Join<B, C> join = root.join("c", JoinType.LEFT);
ParameterExpression<C> managerExpression = builder.parameter(C.class);
ParameterExpression<String> lastnameExpression = builder.parameter(String.class);
Predicate managerEquals = builder.equal(join, managerExpression);
Predicate lastnameEquals = builder.equal(root.get("name"), lastnameExpression);
query = query.select(root).where(builder.and(managerEquals, lastnameEquals));
TypedQuery<B> createQuery = em.createQuery(query);
createQuery.setParameter(managerExpression, null);
createQuery.setParameter(lastnameExpression, "Foo");
createQuery.getResultList();
}
@Test
public void buildQueryFromString() {
Query query2 = em.createQuery("select b from B b where b.c=?1 and b.name=?2");
query2.setParameter(1, null);
query2.setParameter(2, "foo");
query2.getResultList();
}
} |
Frank Tang commented I just checked your test code,and modified test method "buildQueryUsingCriteriaApi" like following: public void buildQueryUsingCriteriaApi() {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<B> query = builder.createQuery(B.class);
Root<B> root = query.from(B.class);
//Join<B, C> join = root.join("c", JoinType.LEFT);
//ParameterExpression<C> managerExpression = builder.parameter(C.class);
ParameterExpression<String> lastnameExpression = builder.parameter(String.class);
//Predicate managerEquals = builder.equal(join, managerExpression);
Predicate managerEquals = builder.equal(root.get("c"),(C)null);
Predicate lastnameEquals = builder.equal(root.get("name"), lastnameExpression);
query = query.select(root).where(builder.and(managerEquals, lastnameEquals));
TypedQuery<B> createQuery = em.createQuery(query);
//createQuery.setParameter(managerExpression, null);
createQuery.setParameter(lastnameExpression, "Foo");
createQuery.getResultList();
} and the generated sql is exactly our expected,it's fine! The difference is i commented using join...So! Can spring data jpa construct criteria without join C in this situation?! |
Ben Li commented HELLO ????? |
Frank Tang commented After dig the source code of Spring Data Jpa...i found the root cause of 'join' ,it's because of method org.springframework.data.jpa.repository.query.QueryUtils#requiresJoin:( ,any association member except anotated with value 'optional = false' will create a join sql phrase...unfortunately, our developers wrote many findByAssociationMember methods and most entity association member
|
If you modeled using And this is what left outer join is for. Essentially, an optional match. Indeed, left outer joins CAN be more expensive. You have the chance of retrieving more data, which costs more in time and memory consumption. But fundamentally, you have to model things as they are and work on optimization after that. If you wish to use the Criteria API to write your own hand-optimized queries, that's fine. But we can't optimize in this fashion AGAINST the modeling annotations of JPA. |
Ben Li opened DATAJPA-942 and commented
I found an issue of spring data jpa. Details are as follow:
When execute the repo “findAllByCAndName(c,name)”, output sql like this:
“select b0_.id as id1_0_, b0_.c_id as c_id3_0_, b0_.name as name2_0_ from b b0_ left outer join c c1_ on b0_.c_id=c1_.id where c1_.id=? and b0_.name=?”
However, my expectation is “select b0_.id as id1_0_, b0_.c_id as c_id3_0_, b0_.name as name2_0_ from b b0_ left outer join c c1_ on b0_.c_id=c1_.id where b0_.c_id=? and b0_.name=?”
The difference between two sql might reduce the sql efficiency greatly. How to change the repo output sql from “where c1_.id=?” to “where b0_.c_id=?” ? Any suggestion will be appreciated.
Here is my demo project, please run it to recur the issue. We are looking forward to your reply. Thanks a lot
Affects: 1.9.4 (Gosling SR4)
Attachments:
Issue Links:
("is duplicated by")
1 votes, 3 watchers
The text was updated successfully, but these errors were encountered: