JPA GAE OneToOne

manuell

Mitglied
Hallo Forum,

ich versuche nun seit geraumer Zeit eine einfache OneToOne-Beziehung ans laufen zu bekommen.
Leider entstehen immer diverse Fehler und ich komme auf keinen grünen Zweig.
Die Herrausforderung ist folgende, ich möchte einen Benutzer anlegen, dann soll der Benutzer durch ein Event ein UserProfil bekommen (d.h. es existiert auch ein Benutzer ohne UserProfile).

Aktuell habe ich folgendes:

Java:
@Entity
public class UserProfile {
	@OneToOne(mappedBy="userProfile")
	private User user; 	
	
	private int id;
	@Id 
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public User getUser() {
		return user;
	}
	public void setUser(User user) {
		this.user = user;
	}
...
und User
Java:
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	private String username;
	private String email;	
	@OneToOne
	private UserProfile userProfile;
	
	
	public UserProfile getUserProfile() {
		return userProfile;
	}
	public void setUserProfile(UserProfile userProfile) {
		this.userProfile = userProfile;
	}
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
...
Beim Anlegen vom Benutzer passiert jetzt folgendes:
Java:
INFO: Local Datastore initialized: 
	Type: Master/Slave
	Storage: C:\Users\manuell\workspace\projekt\war\WEB-INF\appengine-generated\local_db.bin
03.01.2013 07:01:16 com.google.appengine.api.datastore.dev.LocalDatastoreService load
INFO: The backing store, C:\Users\manuell\workspace\projekt\war\WEB-INF\appengine-generated\local_db.bin, does not exist. It will be created.
03.01.2013 07:01:17 org.datanucleus.state.JDOStateManager setPostStoreNewObjectId
SCHWERWIEGEND: java.lang.NullPointerException
03.01.2013 07:01:47 com.google.appengine.api.datastore.dev.LocalDatastoreService$PersistDatastore persist
INFO: Time to persist datastore: 309 ms
Ich habe als id auch schon Long / long als id benutzt, führte allerdings zu anderen Fehlern :)
Wäre super wenn jemand ein funktionierendes Beispiel (für gae) hat.

Danke für die Hilfe
 

Ullenboom

Bekanntes Mitglied
Deine Beziehung ist bidirektional. Hast du beide Seite verbunden? Also so was wie

User u = new User();
UserProfile p = new UserProfile();
u.setUserProfile(p);
p.setUser(u);
 

manuell

Mitglied
Hi,

also den User kann ich problemlos anlegen und auch persistieren.
Allerdings kann ich den Benutzer dann nicht auslesen
so z.B.
Java:
Query query = em.createQuery("SELECT u FROM User u WHERE u.email =:arg1");
		query.setParameter("arg1", email);
		User user;
		user = (User)query.getSingleResult();
aber dann:
Java:
java.lang.NullPointerException
	at com.google.appengine.datanucleus.query.QueryEntityPKFetchFieldManager.fetchLongField(QueryEntityPKFetchFieldManager.java:74)
	at org.datanucleus.identity.IdentityUtils.getApplicationIdentityForResultSetRow(IdentityUtils.java:101)
	at com.google.appengine.datanucleus.EntityUtils.entityToPojo(EntityUtils.java:1009)
Bin mir nicht sicher an welcher Stelle ich das UserProfil setzen soll, brauche es ja erst später und nicht beim ersten persistieren.

Danke für die Hilfe
 

Templarthelast

Bekanntes Mitglied
Hat das Entity für UserProfile auch eine OneToOne Annotation mit einem Userobjekt? Ich vermute, dass du automatisch eager loading hast und beim Auslesen des Users auf das UserProfile geladen werden soll, was nicht gesetzt ist und deshalb eine NPE wirft.

Poste am besten mal die UserProfile Klasse. Als weitere Fehlersuche würde ich mal die OneToOne cascade auf lazy setzen bzw. einfach mal versuchen, ob ich nur den Benutzernamen per Query erhalten kann.

SQL:
SELECT u.username FROM User u WHERE u.email := email
 

manuell

Mitglied
Also,
ich habe die UserProfile jetzt mal etwas angepasst und sie sieht jetzt wie folgt aus:
Java:
@Entity
public class UserProfile {
	@OneToOne(mappedBy="userProfile")
	private User user; 
	
	@Id
	private Key key;
	
	public Key getKey() {
		return key;
	}
	public void setKey(Key key) {
		this.key = key;
	}
	public User getUser() {
		return user;
	}
	public void setUser(User user) {
		this.user = user;
	}
}
Ist jetzt wirklich nur für Testzwecke.
Die User sieht so aus:
Java:
@Entity
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private long id;
	private String username;
	private String email;	
	@OneToOne
	private UserProfile userProfile;
		
	public UserProfile getUserProfile() {
		return userProfile;
	}
	public void setUserProfile(UserProfile userProfile) {
		this.userProfile = userProfile;
	}
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
        public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
}
auch erstmal aufs nötigste reduziert.
Das ist meine EMF-Klasse:
Java:
public class EMF {
    private static final EntityManagerFactory emfInstance = Persistence
            .createEntityManagerFactory("transactions-optional");
 
    private EMF() {
    }
 
    public static EntityManagerFactory get() {
        return emfInstance;
    }
}
so erzeuge ich den User:
Java:
User newUser = new User();
newUser.setUsername(Username);
newUser.setEmail(Email);
EntityManager em = EMF.get().createEntityManager();	
em.persist(newUser);
em.close();
Das klappt noch problemlos. (bis auf ein paar Warnungen)
Sehe gerade das beim Abrufen des Benutzers folgende Warnung kommt:
Java:
The datastore does not support joins and therefore cannot honor requests to place related objects in the default fetch group.  The field will be fetched lazily on first access.  You can modify this warning by setting the datanucleus.appengine.ignorableMetaDataBehavior property in your config.  A value of NONE will silence the warning.  A value of ERROR will turn the warning into an exception.
beim nächsten Abrufen kommt dann der Fehler:
Java:
java.lang.NullPointerException
	at com.google.appengine.datanucleus.query.QueryEntityPKFetchFieldManager.fetchLongField(QueryEntityPKFetchFieldManager.java:74)
	at org.datanucleus.identity.IdentityUtils.getApplicationIdentityForResultSetRow(IdentityUtils.java:101)
	at com.google.appengine.datanucleus.EntityUtils.entityToPojo(EntityUtils.java:1009)

zur Sicherheit hier nochmal die persistence.xml
Java:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

    <persistence-unit name="transactions-optional">
        <provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>
        <properties>
            <property name="datanucleus.NontransactionalRead" value="true"/>
            <property name="datanucleus.NontransactionalWrite" value="true"/>
            <property name="datanucleus.ConnectionURL" value="appengine"/>
        </properties>
    </persistence-unit>
</persistence>

...Bin echt überfragt :)
 

Templarthelast

Bekanntes Mitglied
Die UserProfile Entity hat keine Id Generation Strategy weshalb die Id in der Datenbank nicht gesetzt wird und somit die Verbindung nicht funktionieren kann. Meistens hilft es auch mal die wirkliche generierten Datenbankwerte anschaut. Desweiteren solltest du dem Userobjekt auch ein UserProfile zuweisen.
 

Ähnliche Java Themen


Oben