使用JPA的谷歌应用程序引擎中的双向一对多关系 [英] Bi-directional one-to-many relationship in google app engine using JPA

查看:125
本文介绍了使用JPA的谷歌应用程序引擎中的双向一对多关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在GAE Datastore中创建实体组,使得一个城市包含多个郊区人。以下是我的代码: - $ /
$ b $ p city.java

$ $ p $ @JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class,property =@ id)
@Entity
public class City
{
@Id
private String name;

@OneToMany(mappedBy =city,cascade = CascadeType.ALL)
private Suburban [] suburbans;

public String getName()
{
return name;
}

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

public Suburban [] getSuburbans()
{
return suburbans;
}

public void setSuburbans(Suburban [] suburbans)
{
this.suburbans = suburbans;
}

}

// suburban.java p>

  @JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class,property =@ id)
@Entity
public class Suburban
{

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private key id;

私人字符串名称;

@ManyToOne(fetch = FetchType.LAZY)
私人城市城市;

public City getCity()
{
return city;
}

public void setCity(城市城市)
{
this.city = city;
}

public String getName()
{
return name;
}

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

public key getId()
{
return id;
}
}

我使用google-plugin自动生成cityendpoint类用于eclipse选项生成云端点类。

// CityEndpoint.java

  @Api(name = cityendpoint,namespace = @ApiNamespace(ownerDomain =zestbuds.com,ownerName =zestbuds.com,packagePath =android))
public class CityEndpoint
{

/ **
*此方法列出了插入数据存储中的所有实体。
*它使用HTTP GET方法和分页支持。
*
* @return包含所有实体
*的列表的CollectionResponse类将保持不变,并将光标移至下一页。
* /
@SuppressWarnings({unchecked,unused})
@ApiMethod(name =listCity)
public CollectionResponse< City> listCity(@Nullable @Named(cursor)字符串cursorString,@Nullable @Named(limit)整数限制)
{

EntityManager mgr = null;
游标cursor = null;
列表<城市> execute = null;

尝试
{
mgr = getEntityManager();
Query query = mgr.createQuery(从城市中选择城市);
if(cursorString!= null&& cursorString!=)
{
cursor = Cursor.fromWebSafeString(cursorString);
query.setHint(JPACursorHelper.CURSOR_HINT,cursor);
}

if(limit!= null)
{
query.setFirstResult(0);
query.setMaxResults(limit);
}

execute =(List< City>)query.getResultList();
cursor = JPACursorHelper.getCursor(execute);
if(cursor!= null)
cursorString = cursor.toWebSafeString();

//用于从数据存储中获取所有实体的紧密循环,并容纳
//用于懒惰获取。
(City obj:execute)
;
}终于
{
mgr.close();
}

返回CollectionResponse。< City> 。助洗剂()setItems(执行).setNextPageToken(cursorString).build();
}

/ **
*此方法获取具有主键ID的实体。它使用HTTP GET方法。
*
* @param id java bean的主键。
* @return具有主键ID的实体。
* /
@ApiMethod(name =getCity)
public City getCity(@Named(id)String id)
{
EntityManager mgr = getEntityManager ();
城市城市= null;
尝试
{
city = mgr.find(City.class,id);
}终于
{
mgr.close();
}
返回城市;
}

/ **
*这会在App Engine数据存储中插入一个新实体。如果数据存储中已存在实体
*,则会引发异常。
*它使用HTTP POST方法。
*
* @param city要插入的实体。
* @return插入的实体。
* /
@ApiMethod(name =insertCity)
public City insertCity(City city)
{
EntityManager mgr = getEntityManager();
尝试
{
if(containsCity(city))
{
throw new EntityExistsException(Object already exists);
}
mgr.persist(city);
}终于
{
mgr.close();
}
返回城市;
}

/ **
*此方法用于更新现有实体。如果实体在数据存储中不存在
*,则会引发异常。
*它使用HTTP PUT方法。
*
* @param city要更新的实体。
* @return更新的实体。
* /
@ApiMethod(name =updateCity)
public city updateCity(City city)
{
EntityManager mgr = getEntityManager();
尝试
{
if(!containsCity(city))
{
throw new EntityNotFoundException(Object does not exist);
}
mgr.persist(city);
}终于
{
mgr.close();
}
返回城市;
}

/ **
*此方法删除具有主键ID的实体。
*它使用HTTP DELETE方法。
*
* @param id要删除的实体的主键。
* /
@ApiMethod(name =removeCity)
public void removeCity(@Named(id)String id)
{
EntityManager mgr = getEntityManager ();
尝试
{
City city = mgr.find(City.class,id);
mgr.remove(city);
}终于
{
mgr.close();



私有布尔containsCity(城市城市)
{
EntityManager mgr = getEntityManager();
boolean contains = true;
尝试
{
City item = mgr.find(City.class,city.getName());
if(item == null)
{
contains = false;
}
}终于
{
mgr.close();
}
返回包含;


private static EntityManager getEntityManager()
{
return EMF.get()。createEntityManager();
}

}

最初,我没有使用@ JsonIdentityInfo,因此我得到了 java.io.IOException:com.google.appengine.repackaged.org.codehaus.jackson.map.JsonMappingException:无限递归(StackOverflowError)。在阅读线程后,我发现我的错误是由于杰克逊。



阅读线程,我决定使用@JsonIdentityInfo。现在我得到
java.io.IOException:com.google.appengine.repackaged.org.codehaus.jackson.map.JsonMappingException:您刚刚尝试访问字段suburbans,但该字段不是分离对象时分离。要么不访问此字段,要么在分离对象时将其分离。 (通过引用链:com.google.api.server.spi.response.CollectionResponse [items] - > com.google.appengine.datanucleus.query.StreamingQueryResult [0] - > com.zestbuds.android.City [ suburbans])



即使我使用Cascade.ALL,为什么我的郊区不会被分离?

解决方案

终于解决了问题。



不需要使用@JsonIdentityInfo。我只需要为拥有@ManyToOne批注的类成员移除getter和setter方法(在我的例子中,我移除了getCity()和setCity())。 =https://code.google.com/p/datanucleus-appengine/source/browse/trunk/tests/com/google/appengine/datanucleus/test/jpa/BidirectionalOneToManySubclassesJPA.java =nofollow>这里是datanucleus为双向一对多映射提供的示例。

I want to create entity group in GAE Datastore such that one city have contain multiple suburbans. Following is my code :-

//city.java

@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
@Entity
public class City
{
    @Id
    private String name;

    @OneToMany(mappedBy="city", cascade=CascadeType.ALL)
    private Suburban[] suburbans;

    public String getName()
    {
        return name;
    }

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

    public Suburban[] getSuburbans()
    {
        return suburbans;
    }

    public void setSuburbans(Suburban[] suburbans)
    {
        this.suburbans = suburbans;
    }

}

//suburban.java

@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
@Entity
public class Suburban
{

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Key id;

    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    private City city;

    public City getCity()
    {
        return city;
    }

    public void setCity(City city)
    {
        this.city = city;
    }

    public String getName()
    {
        return name;
    }

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

    public Key getId()
    {
        return id;
    }
}

I am auto-generating cityendpoint class using google-plugin for eclipse option "Generate Cloud Endpoint Class".

//CityEndpoint.java

@Api(name = "cityendpoint", namespace = @ApiNamespace(ownerDomain = "zestbuds.com", ownerName = "zestbuds.com", packagePath = "android"))
public class CityEndpoint
{

    /**
     * This method lists all the entities inserted in datastore.
     * It uses HTTP GET method and paging support.
     *
     * @return A CollectionResponse class containing the list of all entities
     * persisted and a cursor to the next page.
     */
    @SuppressWarnings({ "unchecked", "unused" })
    @ApiMethod(name = "listCity")
    public CollectionResponse<City> listCity(@Nullable @Named("cursor") String cursorString, @Nullable @Named("limit") Integer limit)
    {

        EntityManager mgr = null;
        Cursor cursor = null;
        List<City> execute = null;

        try
        {
            mgr = getEntityManager();
            Query query = mgr.createQuery("select from City as City");
            if (cursorString != null && cursorString != "")
            {
                cursor = Cursor.fromWebSafeString(cursorString);
                query.setHint(JPACursorHelper.CURSOR_HINT, cursor);
            }

            if (limit != null)
            {
                query.setFirstResult(0);
                query.setMaxResults(limit);
            }

            execute = (List<City>) query.getResultList();
            cursor = JPACursorHelper.getCursor(execute);
            if (cursor != null)
                cursorString = cursor.toWebSafeString();

            // Tight loop for fetching all entities from datastore and accomodate
            // for lazy fetch.
            for (City obj : execute)
                ;
        } finally
        {
            mgr.close();
        }

        return CollectionResponse.<City> builder().setItems(execute).setNextPageToken(cursorString).build();
    }

    /**
     * This method gets the entity having primary key id. It uses HTTP GET method.
     *
     * @param id the primary key of the java bean.
     * @return The entity with primary key id.
     */
    @ApiMethod(name = "getCity")
    public City getCity(@Named("id") String id)
    {
        EntityManager mgr = getEntityManager();
        City city = null;
        try
        {
            city = mgr.find(City.class, id);
        } finally
        {
            mgr.close();
        }
        return city;
    }

    /**
     * This inserts a new entity into App Engine datastore. If the entity already
     * exists in the datastore, an exception is thrown.
     * It uses HTTP POST method.
     *
     * @param city the entity to be inserted.
     * @return The inserted entity.
     */
    @ApiMethod(name = "insertCity")
    public City insertCity(City city)
    {
        EntityManager mgr = getEntityManager();
        try
        {
            if (containsCity(city))
            {
                throw new EntityExistsException("Object already exists");
            }
            mgr.persist(city);
        } finally
        {
            mgr.close();
        }
        return city;
    }

    /**
     * This method is used for updating an existing entity. If the entity does not
     * exist in the datastore, an exception is thrown.
     * It uses HTTP PUT method.
     *
     * @param city the entity to be updated.
     * @return The updated entity.
     */
    @ApiMethod(name = "updateCity")
    public City updateCity(City city)
    {
        EntityManager mgr = getEntityManager();
        try
        {
            if (!containsCity(city))
            {
                throw new EntityNotFoundException("Object does not exist");
            }
            mgr.persist(city);
        } finally
        {
            mgr.close();
        }
        return city;
    }

    /**
     * This method removes the entity with primary key id.
     * It uses HTTP DELETE method.
     *
     * @param id the primary key of the entity to be deleted.
     */
    @ApiMethod(name = "removeCity")
    public void removeCity(@Named("id") String id)
    {
        EntityManager mgr = getEntityManager();
        try
        {
            City city = mgr.find(City.class, id);
            mgr.remove(city);
        } finally
        {
            mgr.close();
        }
    }

    private boolean containsCity(City city)
    {
        EntityManager mgr = getEntityManager();
        boolean contains = true;
        try
        {
            City item = mgr.find(City.class, city.getName());
            if (item == null)
            {
                contains = false;
            }
        } finally
        {
            mgr.close();
        }
        return contains;
    }

    private static EntityManager getEntityManager()
    {
        return EMF.get().createEntityManager();
    }

}

Initally, I was not using @JsonIdentityInfo, and hence I was getting java.io.IOException: com.google.appengine.repackaged.org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError). After reading thread, I recognized my error is due to jackson.

After reading Thread, I decided to use @JsonIdentityInfo. Now I am getting java.io.IOException: com.google.appengine.repackaged.org.codehaus.jackson.map.JsonMappingException: You have just attempted to access field "suburbans" yet this field was not detached when you detached the object. Either dont access this field, or detach it when detaching the object. (through reference chain: com.google.api.server.spi.response.CollectionResponse["items"]->com.google.appengine.datanucleus.query.StreamingQueryResult[0]->com.zestbuds.android.City["suburbans"])

why am I getting suburban is not detached, even though I am using Cascade.ALL?

解决方案

Finally solved issue.

There is no need of using @JsonIdentityInfo . I just needed to remove getter and setter method for class member having @ManyToOne annotation(In my case, I removed getCity() and setCity()).

Here is the example provided by datanucleus for bidirectional one-to-many mapping.

这篇关于使用JPA的谷歌应用程序引擎中的双向一对多关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆