2014-03-01 96 views
1

我想使用具有ManyToMany關係的查找器進行查詢,並沒有能夠解決這個問題。使用play 2.1.2和ebean 3.1.1(與Play一起打包)。ManyToMany查詢使用播放和ebean

我有一個MyUser類,它有MyContacts和MyContactGroups。 MyContactGroups有一個ManyToMany和MyContact。我正在嘗試編寫一個查詢,讓我可以獲取MyUser的MyContactGroup中的所有MyContacts。下面的查詢方法失敗的是findByContactGroupAndUser。

實體有:

@Entity 
@Table(name = "my_user") 
public class MyUser extends Model { 

    @Id 
    public Long id; 

    public String name; 

    @OneToMany(cascade = CascadeType.ALL) 
    public List<MyContact> myContacts = new ArrayList<MyContact>(); 

    @OneToMany(cascade = CascadeType.ALL) 
    public List<MyContactGroup> myContactGroups = new ArrayList<MyContactGroup>(); 

    public void addContact(MyContact myContact) { 
     myContacts.add(myContact); 
    } 

    public void addContactGroup(MyContactGroup myContactGroup) { 
     myContactGroups.add(myContactGroup); 
    } 
    public static Model.Finder<Long, MyUser> find = new Model.Finder<Long, MyUser>(
      Long.class, MyUser.class); 
} 

@Entity 
@Table(name = "my_contact") 
public class MyContact extends Model { 
    @Id 
    public Long id; 
    public String name; 

    @ManyToOne 
    public MyUser myUser; 

    @ManyToMany(mappedBy = "myContacts") 
    public MyContactGroup myContactGroup; 

    public static Model.Finder<Long, MyContact> find = new Model.Finder<Long, MyContact>(
      Long.class, MyContact.class); 

    public static Page<MyContact> findByContactGroupAndUser(MyUser myUser, MyContactGroup myContactGroup, int pageSize, int page) { 
     return find.where(Expr.and(Expr.eq("myContactGroup", myContactGroup), 
        Expr.eq("myUser", myUser))) 
        .findPagingList(pageSize).setFetchAhead(false).getPage(page); 
    } 
} 

@Entity 
@Table(name = "my_contact_group") 
public class MyContactGroup extends Model { 
    @Id 
    public Long id; 

    public String name; 

    @ManyToOne(cascade = CascadeType.ALL) 
    public MyUser myUser; 

    @ManyToMany(cascade = CascadeType.ALL) 
    public List<MyContact> myContacts = new ArrayList<MyContact>(); 


    public void addContact(MyContact myContact) { 
     myContacts.add(myContact); 
    } 

    public static Model.Finder<Long, MyContactGroup> find = new Model.Finder<Long, MyContactGroup>(
      Long.class, MyContactGroup.class); 
} 

測試:

@Test 
    public void testMyContactGroup() { 
     MyUser myUser = new MyUser(); 
     myUser.name = "UserSteve"; 
     myUser.save(); 

     MyContact myContact = new MyContact(); 
     myContact.name = "ContactBob"; 
     myContact.myUser = myUser; 

     myUser.addContact(myContact); 
     myUser.save(); 

     assertThat(MyUser.find.where().eq("name", "UserSteve").findUnique().name.equals("UserSteve")); 
     assertThat(myUser.myContacts.get(0).name.equals("ContactBob")); 

     MyContactGroup myContactGroup = new MyContactGroup(); 
     myContactGroup.name = "myContactGroup"; 
     myContactGroup.myUser = myUser; 

     myUser.addContactGroup(myContactGroup); 
     myUser.update(); 
     assertThat(myUser.myContactGroups.get(0).name.equals("myContactGroup")); 
     myContactGroup = myUser.myContactGroups.get(0); 
     myContactGroup.addContact(myContact); 


     myUser.update(); 
     Ebean.saveManyToManyAssociations(myContactGroup, "myContacts"); 
     myUser = MyUser.find.where().eq("name", "UserSteve").findUnique(); 
     assertThat(myUser.myContactGroups.get(0).name.equals("myContactGroup")); 
     assertThat(myUser.myContactGroups.get(0).myContacts.get(0).name.equals("ContactBob")); 


     myUser = MyUser.find.where().eq("name", "UserSteve").findUnique(); 
     myContactGroup = myUser.myContactGroups.get(0); 
     assertThat(myContactGroup.name.equals("myContactGroup")); 
     assertThat(myUser.myContactGroups.get(0).myContacts.get(0).name.equals("ContactBob")); 
     log.info("doing lookup"); 

     Page<MyContact> page = MyContact.findByContactGroupAndUser(myUser, myContactGroup, 10, 0); 
     assertThat(page.getList().size() == 1); 
} 

例外:

javax.persistence.PersistenceException: java.util.concurrent.ExecutionException: java.lang.NullPointerException 
    at com.avaje.ebeaninternal.server.query.LimitOffsetPage.getList(LimitOffsetPage.java:64) 
    at ApplicationTest.testMyContactGroup(ApplicationTest.java:152) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:202) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:65) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) 
Caused by: java.util.concurrent.ExecutionException: java.lang.NullPointerException 
    at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:252) 
    at java.util.concurrent.FutureTask.get(FutureTask.java:111) 
    at com.avaje.ebeaninternal.server.query.BaseFuture.get(BaseFuture.java:29) 
    at com.avaje.ebeaninternal.server.query.LimitOffsetPage.getList(LimitOffsetPage.java:62) 
    ... 29 more 
Caused by: java.lang.NullPointerException 
    at com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne.getAssocOneIdValues(BeanPropertyAssocOne.java:411) 
    at com.avaje.ebeaninternal.server.expression.SimpleExpression.addBindValues(SimpleExpression.java:50) 
    at com.avaje.ebeaninternal.server.expression.LogicExpression.addBindValues(LogicExpression.java:56) 
    at com.avaje.ebeaninternal.util.DefaultExpressionList.buildBindValues(DefaultExpressionList.java:277) 
    at com.avaje.ebeaninternal.server.query.CQueryPredicates.prepare(CQueryPredicates.java:281) 
    at com.avaje.ebeaninternal.server.query.CQueryPredicates.prepare(CQueryPredicates.java:263) 
    at com.avaje.ebeaninternal.server.query.CQueryBuilder.buildQuery(CQueryBuilder.java:200) 
    at com.avaje.ebeaninternal.server.query.CQueryEngine.findMany(CQueryEngine.java:162) 
    at com.avaje.ebeaninternal.server.query.DefaultOrmQueryEngine.findMany(DefaultOrmQueryEngine.java:77) 
    at com.avaje.ebeaninternal.server.core.OrmQueryRequest.findList(OrmQueryRequest.java:272) 
    at com.avaje.ebeaninternal.server.core.DefaultServer.findList(DefaultServer.java:1502) 
    at com.avaje.ebeaninternal.server.query.CallableQueryList.call(CallableQueryList.java:26) 
    at com.avaje.ebeaninternal.server.query.CallableQueryList.call(CallableQueryList.java:15) 
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:166) 
    at com.avaje.ebeaninternal.server.lib.thread.PooledThread.doTheWork(PooledThread.java:89) 
    at com.avaje.ebeaninternal.server.lib.thread.PooledThread.run(PooledThread.java:62) 
    at java.lang.Thread.run(Thread.java:722) 

回答

1

我認爲這基本上是因爲我還沒有把的mappedBy上正確的實體,並可能將Ebean直接字段訪問與setter/getter訪問混合。在遊戲中他們說你應該只使用setter/getter訪問權限,因爲play和Ebean代碼增強之間存在一些衝突。以下直接與Ebean一起工​​作,我也能夠在工作中發揮作用。

package app.data; 

import com.avaje.ebean.validation.Length; 

import javax.persistence.*; 
import java.util.ArrayList; 
import java.util.List; 

/** 
* Created by aakture on 3/2/14. 
*/ 
@Entity 
@Table(name="o_user") 
public class User { 

    @Id 
    Integer id; 

    @Length(max = 20) 
    String name; 

    @OneToMany(cascade = CascadeType.ALL) 
    List<ContactGroup> contactGroups = new ArrayList<ContactGroup>(); 

    @OneToMany(cascade = CascadeType.ALL) 
    List<Contact> contacts = new ArrayList<Contact>(); 

    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public List<ContactGroup> getContactGroups() { 
     return contactGroups; 
    } 

    public void setContactGroups(List<ContactGroup> contactGroups) { 
     this.contactGroups = contactGroups; 
    } 

    public List<Contact> getContacts() { 
     return contacts; 
    } 

    public void setContacts(List<Contact> contacts) { 
     this.contacts = contacts; 
    } 

    @Override 
    public String toString() { 
     return com.google.common.base.Objects.toStringHelper(this) 
       .add("id", id) 
       .add("name", name) 
       .add("contactGroups", contactGroups) 
       .toString(); 
    } 
} 


package app.data; 

import javax.persistence.*; 
import java.util.ArrayList; 
import java.util.List; 

/** 
* Created by aakture on 3/2/14. 
*/ 
@Entity 
@Table(name="o_contact") 
public class Contact { 
    @Id 
    Integer id; 

    String name; 

    @ManyToOne 
    User user; 

    @ManyToMany 
    List<ContactGroup> contactGroups = new ArrayList<ContactGroup>(); 

    public List<ContactGroup> getContactGroups() { 
     return contactGroups; 
    } 

    public void setContactGroups(List<ContactGroup> contactGroups) { 
     this.contactGroups = contactGroups; 
    } 

    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public User getUser() { 
     return user; 
    } 

    public void setUser(User user) { 
     this.user = user; 
    } 


} 



package app.data; 

import javax.persistence.*; 
import java.util.ArrayList; 
import java.util.List; 

/** 
* Created by aakture on 3/2/14. 
*/ 
@Entity 
@Table(name="o_contact_group") 
public class ContactGroup { 

    @Id 
    Integer id; 

    @ManyToOne 
    User user; 

    String name; 
    @ManyToMany(cascade = CascadeType.MERGE, mappedBy = "contactGroups") 
    List<Contact> contacts = new ArrayList<Contact>(); 

    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    public User getUser() { 
     return user; 
    } 

    public void setUser(User user) { 
     this.user = user; 
    } 

    public List<Contact> getContacts() { 
     return contacts; 
    } 

    public void setContacts(List<Contact> contacts) { 
     this.contacts = contacts; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
} 

測試:

public void test() { 
     User user = new User(); 
     user.setName("UserBob"); 
     Ebean.save(user); 



     ContactGroup contactGroup = new ContactGroup(); 
     contactGroup.setName("Friends"); 

     List<ContactGroup> contactGroupList = new ArrayList<ContactGroup>(); 
     contactGroupList.add(contactGroup); 
     user.setContactGroups(contactGroupList); 

     Ebean.update(user); 

     user = Ebean.find(User.class).where().eq("name", "UserBob").findUnique(); 
     List<ContactGroup> contactGroups = user.getContactGroups(); 

     for(ContactGroup cg : contactGroups) { 
      System.out.println("contactGroup: " + cg.getName()); 
     } 

     Contact contact = new Contact(); 
     contact.setName("ContactSteve"); 
     user.getContacts().add(contact); 

     Ebean.update(user); 

     user = Ebean.find(User.class).where().eq("name", "UserBob").findUnique(); 
     for(Contact c : user.getContacts()) { 
      System.out.println("contact: " + c.getName()); 
     } 
     Contact contactSteve = user.getContacts().get(0); 
     ContactGroup friends = user.getContactGroups().get(0); 
     friends.getContacts().add(contactSteve); 

     Ebean.saveManyToManyAssociations(friends, "contacts"); 

     Ebean.update(user); 
     user = Ebean.find(User.class).where().eq("name", "UserBob").findUnique(); 

     friends = user.getContactGroups().get(0); 
     List<Contact> contacts = friends.getContacts(); 
     for (Contact c : contacts) { 
      System.out.println("contact: " + c.getName()); 
     } 

     contact = Ebean.find(Contact.class).where().and(Expr.eq("user.name", "UserBob"), Expr.eq("contactGroups.name", "Friends")).findUnique(); 

     System.out.println("contact: " + contact.getName()); 
}