Persistance JDO - Как запросить свойство коллекции с помощью JDOQL? - PullRequest
4 голосов
/ 03 марта 2010

Я хочу создать приложение, в котором пользователь, идентифицируемый по адресу электронной почты, может иметь несколько учетных записей приложения. Каждая учетная запись может иметь одного или нескольких пользователей. Я пытаюсь использовать возможности JDO Storage с Google App Engine Java. Вот моя попытка:

@PersistenceCapable
@Inheritance(strategy = InheritanceStrategy.NEW_TABLE)
public class AppAccount {
     @PrimaryKey
     @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
     private Long id;

    @Persistent
    private String companyName;

    @Persistent
    List<Invoices> invoices = new ArrayList<Invoices>();

    @Persistent
    List<AppUser> users = new ArrayList<AppUser>();

    // Getter Setters and Other Fields
}

@PersistenceCapable
@EmbeddedOnly
public class AppUser {

    @Persistent
    private String username;

    @Persistent
    private String firstName;

    @Persistent
    private String lastName;

     // Getter Setters and Other Fields
}

Когда пользователь входит в систему, я хочу проверить, к каким учетным записям он принадлежит. Если он или она принадлежит более чем одному, то ему или ей будет предоставлена ​​панель управления, где он / она может щелкнуть по какой учетной записи он / она хочет загрузить. Это мой код для получения списка учетных записей приложений, в которых он зарегистрирован.

public static List<AppAccount> getUserAppAccounts(String username) {
    PersistenceManager pm = JdoUtil.getPm();
    Query q = pm.newQuery(AppAccount.class);
    q.setFilter("users.username == usernameParam");
    q.declareParameters("String usernameParam");
    return (List<AppAccount>) q.execute(username);
}

Но я получаю следующую ошибку:

SELECT FROM invoices.server.AppAccount WHERE users.username == usernameParam PARAMETERS String usernameParam: Encountered a variable expression that isn't part of a join.  Maybe you're referencing a non-existent field of an embedded class.
org.datanucleus.store.appengine.FatalNucleusUserException: SELECT FROM com.softamo.pelicamo.invoices.server.AppAccount WHERE users.username == usernameParam PARAMETERS String usernameParam: Encountered a variable expression that isn't part of a join.  Maybe you're referencing a non-existent field of an embedded class.
    at org.datanucleus.store.appengine.query.DatastoreQuery.getJoinClassMetaData(DatastoreQuery.java:1154)
    at org.datanucleus.store.appengine.query.DatastoreQuery.addLeftPrimaryExpression(DatastoreQuery.java:1066)
    at org.datanucleus.store.appengine.query.DatastoreQuery.addExpression(DatastoreQuery.java:846)
    at org.datanucleus.store.appengine.query.DatastoreQuery.addFilters(DatastoreQuery.java:807)
    at org.datanucleus.store.appengine.query.DatastoreQuery.performExecute(DatastoreQuery.java:226)
    at org.datanucleus.store.appengine.query.JDOQLQuery.performExecute(JDOQLQuery.java:85)
    at org.datanucleus.store.query.Query.executeQuery(Query.java:1489)
    at org.datanucleus.store.query.Query.executeWithArray(Query.java:1371)
    at org.datanucleus.jdo.JDOQuery.execute(JDOQuery.java:243)
    at com.softamo.pelicamo.invoices.server.Store.getUserAppAccounts(Store.java:82)
    at com.softamo.pelicamo.invoices.test.server.StoreTest.testgetUserAppAccounts(StoreTest.java:39)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Есть идеи?

Я неправильно понимаю, что JDO настаивает?

1 Ответ

5 голосов
/ 05 апреля 2010

Класс AppAccount имеет переменную users, равную List. List не имеет свойства имени пользователя напрямую.

Вам нужно сделать что-то вроде этого:

@PersistenceCapable
@EmbeddedOnly
public class AppUser {

    @Persistent
    private String username;

    @Persistent
    private String firstName;

    @Persistent
    private String lastName;

    //override equals method for List .contains
    @Override
    public boolean equals(AppUser au) {
        return au.getUsername().equals(this.username);
    } 

     // Getter Setters and Other Fields
}

Query q = pm.newQuery(AppAccount.class);
//the : denotes an implicit variable will be passed to query execute method
q.setFilter("users.contains(:username)");
//create a new AppUser with the username you want to check, this query will find the AppAccount with any AppUser with the same username, because the .equals method of AppUser has been overridden to return true based on the username member variable
List<AppAccount> results = (List<AppAccount>)query.execute(new AppUser(username));
...