Sql jpa Query for ManyToOne
извините за мой плохой английский и может быть плохой вопрос. У меня есть это:
сущность
@Entity
@Table(name = "Books")
@NamedQueries({
@NamedQuery(name = "BooksEntity.findAll", query = "SELECT u FROM BooksEntity u"),
@NamedQuery(name = "BooksEntity.findByBookId", query = "SELECT u FROM BooksEntity u WHERE u.book_id = :book_id"),
@NamedQuery(name = "BooksEntity.findByTitle", query = "SELECT u FROM BooksEntity u WHERE u.title = :title")})
public class BooksEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "book_id",unique=true, nullable=false)
@GeneratedValue(strategy = GenerationType.TABLE)
private Long book_id;
@ManyToOne
@JoinColumn(name = "author", nullable=true)
private AuthorsEntity author;
@OneToMany (mappedBy="book")
private List<UsersEntity> users;
//set and get
}
@Entity
@Table(name = "Users")
@NamedQueries({
@NamedQuery(name = "UsersEntity.findAll", query = "SELECT u FROM UsersEntity u"),
@NamedQuery(name = "UsersEntity.findByUserId", query = "SELECT u FROM UsersEntity u WHERE u.user_id = :user_id"),
@NamedQuery(name = "UsersEntity.findByUserIdAndPassword", query = "SELECT u FROM UsersEntity u WHERE u.user_id = :user_id AND u.password = :password"),
@NamedQuery(name = "UsersEntity.findByName", query = "SELECT u FROM UsersEntity u WHERE u.name = :name"),
@NamedQuery(name = "UsersEntity.findByNameAndPassword", query = "SELECT u FROM UsersEntity u WHERE u.name = :name AND u.password = :password"),
@NamedQuery(name = "UsersEntity.findByEmail", query = "SELECT u FROM UsersEntity u WHERE u.email = :email")})
public class UsersEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "user_id", unique=true, nullable=false)
@GeneratedValue(strategy = GenerationType.TABLE)
private Long user_id;
@Column(name = "name", nullable = false, unique = true)
private String name;
@ManyToOne
@JoinColumn(name = "book")
private BooksEntity book;
}
И менеджер
@Stateless
public class BookManager implements BookManagerLocal {
@PersistenceContext
EntityManager em;
@EJB
UserManagerLocal um;
@Override
public List<BooksEntity> getAllBooks() {
List<BooksEntity> books = em.createNamedQuery("BooksEntity.findAll").getResultList();
if (!books.isEmpty()) {
return books;
} else {
return null;
}
}
@Override
public List<BooksEntity> getAllBooksUser(String name) {
List<UsersEntity> users;
List<BooksEntity> books = this.getAllBooks();
if (books.isEmpty()) {
return null;
} else {
List<BooksEntity> userbooks = new ArrayList<BooksEntity>();
for (BooksEntity book : books) {
users = book.getUsers();
for (UsersEntity user : users) {
if (name.equals(user.getName())) {
userbooks.add(book);
}
}
}
if (!userbooks.isEmpty()) {
return userbooks;
} else {
return null;
}
}
}
}
Мне нужно иметь все книги для одного пользователя. Но у меня есть проблема с этим. Я делаю так
@Override
public List<BooksEntity> getAllBooks() {
List<BooksEntity> books = em.createNamedQuery("BooksEntity.findAll").getResultList();
if (!books.isEmpty()) {
return books;
} else {
return null;
}
}
@Override
public List<BooksEntity> getAllBooksUser(String name) {
List<UsersEntity> users;
List<BooksEntity> books = this.getAllBooks();
if (books.isEmpty()) {
return null;
} else {
List<BooksEntity> userbooks = new ArrayList<BooksEntity>();
for (BooksEntity book : books) {
users = book.getUsers();
for (UsersEntity user : users) {
if (name.equals(user.getName())) {
userbooks.add(book);
}
}
}
if (!userbooks.isEmpty()) {
return userbooks;
} else {
return null;
}
}
}
Но это не работает. у меня есть ejbexception и nullpointexception.
WARNING: EJB5184:A system exception occurred during an invocation on EJB BookManager, method: public java.util.List book.ejb.BookManager.getAllBooksUser(java.lang.String)
WARNING: javax.ejb.EJBException
at com.sun.ejb.containers.BaseContainer.processSystemException(BaseContainer.java:5215)
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5113)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4901)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2045)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1994)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:222)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:89)
at $Proxy230.getAllBooksUser(Unknown Source)
at book.bean.BookEditBean.getUserBooks(BookEditBean.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at javax.el.BeanELResolver.getValue(BeanELResolver.java:363)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
at com.sun.el.parser.AstValue.getValue(AstValue.java:138)
at com.sun.el.parser.AstValue.getValue(AstValue.java:183)
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:224)
at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
at com.sun.faces.facelets.component.UIRepeat.getValue(UIRepeat.java:273)
at com.sun.faces.facelets.component.UIRepeat.getDataModel(UIRepeat.java:249)
at com.sun.faces.facelets.component.UIRepeat.setIndex(UIRepeat.java:443)
at com.sun.faces.facelets.component.UIRepeat.process(UIRepeat.java:482)
at com.sun.faces.facelets.component.UIRepeat.encodeChildren(UIRepeat.java:984)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1757)
at javax.faces.render.Renderer.encodeChildren(Renderer.java:168)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1757)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1760)
at javax.faces.render.Renderer.encodeChildren(Renderer.java:168)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1757)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1760)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1760)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:402)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.NullPointerException
at book.ejb.BookManager.getAllBooksUser(BookManager.java:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1052)
at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1124)
at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:5388)
at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:619)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:571)
at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:861)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:571)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doAround(SystemInterceptorProxy.java:162)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:144)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:861)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:370)
at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:5360)
at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:5348)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:214)
... 61 more
Вы можете мне помочь? Спасибо за всех вас.
1 ответ
Вы используете плохую практику, и, используя ее, вы оказываете непосредственное влияние. Метод, возвращающий List (или любой вид коллекции), никогда не должен возвращать null. Он должен вернуть пустой список, если нечего возвращать. Возвращая значение null, вы заставляете каждого вызывающего абонента, включая себя, всегда проверять наличие нулевого значения перед использованием возвращенного списка, чего вы не смогли сделать:
List<BooksEntity> books = this.getAllBooks();
if (books.isEmpty()) {
return null;
}
В приведенном выше коде вы не проверяете, books
ноль перед вызовом isEmpty()
, И с тех пор getAllBooks()
возвращает пустой список вместо пустого списка, если книга не найдена, вы получаете исключение NullPointerException.
Вот как я бы переписал ваш код:
@Override
public List<BooksEntity> getAllBooks() {
return em.createNamedQuery("BooksEntity.findAll").getResultList();
}
@Override
public List<BooksEntity> getAllBooksUser(String name) {
List<BooksEntity> books = this.getAllBooks();
List<BooksEntity> userbooks = new ArrayList<BooksEntity>();
for (BooksEntity book : books) {
users = book.getUsers();
for (UsersEntity user : users) {
if (name.equals(user.getName())) {
userbooks.add(book);
}
}
}
return userBooks;
}
Обратите внимание, что код намного короче, и как он не может создать исключение NullPointerException.
Тем не менее, ваш метод поиска книг для данного имени пользователя крайне неэффективен: вы загружаете каждую книгу (представьте, что делаете это с реальной библиотекой), а для каждой книги вы загружаете всех ее пользователей.
Было бы гораздо эффективнее найти всех пользователей с заданным именем (используя findByName
именованный запрос, например) и вернуть их книгу. Или еще лучше сделать все это одним JPQL-запросом:
select book from UsersEntity user
inner join user.book book
where user.name = :name
Метод будет выглядеть следующим образом:
public List<BooksEntity> getAllBooksUser(String name) {
String jpql =
"select book from UsersEntity user"
+ " inner join user.book book"
+ " where user.name = :name";
return em.createTypedQuery(jpql, BooksEntity.class)
.setParameter("name", name)
.getResultList();
}
Наконец, ваш код был бы более читабельным, если бы вы назвали свои объекты Book
а также User
, вместо BooksEntity
а также UsersEntity
, Использование формы множественного числа для одного пользователя или книги - действительно плохая идея. И Entity
суффикс раздражает шум.