4 votes

Persistance JDO - Comment interroger une propriété d'une collection avec JDOQL ?

Je veux construire une application où un utilisateur identifié par une adresse e-mail peut avoir plusieurs comptes d'application. Chaque compte peut avoir un ou plusieurs utilisateurs. J'essaie d'utiliser les capacités de stockage JDO avec Google App Engine Java. Voici ma tentative :

@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
}

Lorsqu'un utilisateur se connecte, je veux vérifier à combien de comptes il appartient. S'il appartient à plus d'un compte, un tableau de bord lui sera présenté et il pourra cliquer sur le compte qu'il souhaite charger. Voici mon code pour récupérer la liste des comptes d'applications où il/elle est enregistré(e).

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);
}

Mais je reçois l'erreur suivante :

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)

Des idées ?

Est-ce que je me trompe complètement sur la persistance JDO ?

5voto

Finbarr Points 8420

El AppAccount a un users qui est une List . Le site List n'a pas directement une propriété de nom d'utilisateur.

Vous devez faire quelque chose comme ça :

@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));

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X