JPA Map<String, OtherEntity>; kulcsa NULL lesz az adatbázisban

Fórumok

Tovább próbálkozom JPA-val (előző). Most szintén egy szintetikus osztályban szeretnék négyfajta Map-et tesztelni:

Map<String, String>, Map<String, OtherEntity2>, Map<OtherEntity1, String>, Map<OtherEntity1, OtherEntity2>

Az első, és meglepetésemre az utolsó kettő hibátlanul működik, azonban a második Map-et nem tudom persisztálni, azaz a String kulcshoz saját entitásosztályt rendelő Map-et.

A kód a következő:


@Entity
public class Adatlap implements Serializable {
    /* ... */
    @ManyToMany(fetch=FetchType.EAGER)
    private Map<String, Valasz> szoveg_valasz;
    /* ... */
}

Ahol a Valasz osztály egy jól működő entitásosztály.

A szindróma a következő: Hiba nélkül tudom kódból persisztálni az adott entitásosztályt, majd visszatölteni. Miután a kódban két bejegyzést hozzáadok a Map-hez, az adatbázisban a következő sorok lesznek:


mysql> SELECT *
    -> FROM `ADATLAP_VALASZ`
    -> LIMIT 0 , 30;
+------------+------------------+-------------------+
| Adatlap_ID | szoveg_valasz_ID | SZOVEG_VALASZ_KEY |
+------------+------------------+-------------------+
|         57 |               55 | NULL              |
|         57 |               54 | NULL              |
+------------+------------------+-------------------+

Azaz valamiért a SZOVEG_VALASZ_KEY (varchar típusúként hozza létre), azaz a Map String típusú kulcsa NULL-ként íródik be az adatbázisba. Igen, ez azt jelenti, hogy az adatbázisban nincs meg az érték, mégis vissza tudom tölteni az entitásmenedzserből! Miután flush-solom a Connection Poolt, azután jönnek majd a hibaüzenetek:


(Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.QueryException
Exception Description: The field [ADATLAP.SZOVEG_VALASZ_KEY] in this expression has an invalid table in this context.

Próbálkozásaim:

  • Integer kulccsal ugyanez a helyzet
  •     @ManyToMany(fetch=FetchType.EAGER, targetEntity=Valasz.class)
        @MapKeyClass(String.class)

    annotációkkal ugzanez a helyzet

  • @MapKeyColumn

    annotációval még az oszlopnevet is átállíthatom, az újba is NULL-t ír

  • @ElemntCOllection

    annotáció nyílván nem játszik, mivel az érték saját entitás

A Java EE tutorial megfelelő bejegyzése szerint "By default, the name attribute of @MapKeyColumn is of the form RELATIONSHIP FIELD/PROPERTY NAME_KEY. For example, if the referencing relationship field name is image, the default name attribute is IMAGE_KEY.", ez meg is történik, csak épp NULL a beleírt érték.

A legidegesítőbb, hogy ha ezt a Stringet egy Entitásosztállyal wrappelem, akkor működik ugyebár (lásd Map<OtherEntity1, String>).

Kérdésem az lenne, hogy milyen annotáció/PersistenceProvider beállítás szükséges ahhoz, hogy ez az egyszerűnek hitt mapping működjön?

(GlassFish v3, Eclipse Persistence Services - 2.0.1)

Hozzászólások

Up(1) - Nyílván egy StringWrapper entitásosztály megoldaná a problémát, de ez elég csúnya megoldás.

Tranzakciókezelés van e?

Az Adatlap és Valasz objektumokat külön mented, vagy egyben mented az egészet? Esetleg másold be azt a részletet, ahol a mentést végzed.

Nekem ez elég fura, hogy "ADATLAP.SZOVEG_VALASZ_KEY"-ra panaszkodik, amikor az Adatlap táblán nem is kell, hogy legyen olyan oszlop.

Kipróbáltam nálam és működött szépen (igaz ez egy hibernate-s springes alkalmazás, de ez is ugyanúgy JPA 2.0):


public class AdatlapDao {
@PersistenceContext
private EntityManager em;
@Transactional
public Adatlap generateRandomAdatlap() {
Valasz valasz1 = new Valasz();
Valasz valasz2 = new Valasz();
em.persist(valasz1);
em.persist(valasz2);
Adatlap adatlap = new Adatlap();
adatlap.setValaszok(new HashMap<String, Valasz>());
adatlap.getValaszok().put("foo", valasz1);
adatlap.getValaszok().put("bar", valasz2);
em.persist(adatlap);
return adatlap;
}
}

Szépen lementette az entitásokat is meg a kapcsolataikat is (a map kulcsokat is).

Hát igen, elég fura, főleg azért, mert olyan nincs, hogy ADATLAP.SZOVEG_VALASZ_KEY, viszont olyan lenne, hogy ADATLAP_VALASZ.SZOVEG_VALASZ_KEY ... :\

A kód, ami a perzisztálást végzi, a NetBeans által generált JPA controller class, amely sejtésem szerint tranzakciókezeléssel csinálja.

public AdatlapJpaController() {
        emf = Persistence.createEntityManagerFactory("AdatlapPU");
}
private EntityManagerFactory emf = null;

public EntityManager getEntityManager() {
        return emf.createEntityManager();
}

public void create(Adatlap adatlap) {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            em.persist(adatlap);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

Más sem nagyon szív ezzel, nekem egyre gyanúsabb, hogy az EclipseLink a bugos. De hát az a referencia implementáció, nem?

Azt megintcsak megköszönném.

Szerkesztve: Annyit még mindenképpen megemlítenék, hogy az ADATLAP_VALASZ.SZOVEG_VALASZ_KEY oszlop varchar(255)-ként jött létre, tehát ez a legidegesítőbb, hogy kb. oda csak be kéne írnia a kulcs szövegét. Csakhát ez a "The field [ADATLAP.SZOVEG_VALASZ_KEY] in this expression has an invalid table in this context." Üzenet...

Fejlemény:
Az én tippem az volt, hogy EclipseLink bugos, ebben már egyre biztosabb vagyok, tekintve, hogy pár kattintás és némi kódhegesztés után a persistence providert Hibernate-re állítva minden működik az elvárt módon...

Ettől függetlenül az IDE-támogatás miatt továbbra is érdekelne az EclipseLink-es megoldás is.