首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用JPA在实体内持久化Map (java.util.Map)对象,并确保持久化级联?

如何使用JPA在实体内持久化Map (java.util.Map)对象,并确保持久化级联?
EN

Stack Overflow用户
提问于 2011-09-23 04:39:06
回答 1查看 14.7K关注 0票数 9

我最近开始玩这出戏了!Framework for Java,版本1.2.3 (最新)。在测试框架时,当我试图在一个名为FooSystem的Hibernate实体中持久化一个Map对象时,我遇到了一个奇怪的问题。Map对象使用Map<Long, Foo> fooMap;声明将一个long映射到一个称为Foo的Hibernate实体

我的问题如下:正确的表是按照我注释的那样创建的。但是,当FooSystem对象fs被持久化时,fs.fooMap中的数据就不是了!

下面是我为实体使用的代码。首先是Foo

代码语言:javascript
运行
复制
package models.test;

import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import play.db.jpa.Model;

@Entity
public class Foo extends Model
{
    @ManyToOne
    private FooSystem foosystem;

    public Foo(FooSystem foosystem)
    {
        this.foosystem = foosystem;
    }
}

这是FooSystem

代码语言:javascript
运行
复制
package models.test;

import java.util.HashMap;
import java.util.Map;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import play.db.jpa.Model;

@Entity
public class FooSystem extends Model
{
    @ManyToMany(cascade = {CascadeType.ALL, CascadeType.PERSIST})
    @JoinTable(
        name = "fooMap",
        joinColumns = @JoinColumn(name = "foosystem"),
        inverseJoinColumns = @JoinColumn(name = "foo")
    )
    private Map<Long, Foo> fooMap = new HashMap<Long, Foo>();

    public FooSystem()
    {
        Foo f1 = new Foo(this);
        Foo f2 = new Foo(this);
        fooMap.put(f1.getId(), f1);
        fooMap.put(f2.getId(), f2);
    }

    public Map<Long, Foo> getFooMap()
    {
        return fooMap;
    }
}

下面是我用来测试设置的Controller类:

代码语言:javascript
运行
复制
package controllers;

import javax.persistence.EntityManager;
import models.test.FooSystem;
import play.db.jpa.JPA;
import play.mvc.Controller;

public class TestController extends Controller
{
    public static void index() {
        EntityManager em = JPA.em();
        FooSystem fs = new FooSystem();
        em.persist(fs);
        render();
    }
}

这出戏!框架自动为HTTP请求创建了一个事务。尽管数据被插入到foofoosystem表中,但是没有任何东西被插入到foomap表中,这是预期的结果。对此我能做些什么呢?我遗漏了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-09-24 01:24:01

我使用Java Ka Baby的建议解决了这个问题。问题实际上不在我的Model类中;问题出在Controller中。具体地说,我以错误的顺序保存实体。一旦我意识到在Map<Long, Foo>上使用@ElementCollection注释产生了与我手动指定的连接表相同的效果,我就试着重新思考如何保存实体的实验。

在我上面发布的代码中,您可以在FooSystem构造函数中看到,两个Foo对象f1f2在持久化Foo对象之前被放入fooMap。我意识到,如果f1在被放入映射时不在数据库中,那么它如何能够将其ID用作连接表中的外键?

如果您能理解我的推理方向,就会发现显而易见的答案是JPA无法完成使用外键引用不存在的键这一惊人的壮举。奇怪的是这出戏!对于我发布的原始代码,console根本没有注意到任何错误,即使它根本不正确。要么是框架吞噬了过程中抛出的每个Exception,要么是我编写了应该生成Exception的代码。

因此,为了解决这个问题,我在对Foo实体执行任何操作之前对它们进行了持久化。只有在那时,我才将它们放入fooMap。最后,填充fooMap之后,我持久化了FooSystem实体。

以下是更正后的TestController类:

代码语言:javascript
运行
复制
package controllers;

import javax.persistence.EntityManager;
import models.test.Foo;
import models.test.FooSystem;
import play.db.jpa.JPA;
import play.mvc.Controller;

public class TestController extends Controller
{
    public static void index() {
        EntityManager em = JPA.em();
        FooSystem fs = new FooSystem();
        Foo f1 = new Foo(fs);
        Foo f2 = new Foo(fs);
        f1.save();
        f2.save();
        fs.put(f1.getId(), f1);
        fs.put(f2.getId(), f2);
        fs.save();
        render();
    }
}

而且,由于我更改了FooSystem,下面是该类的最终代码:

代码语言:javascript
运行
复制
package models.test;

import java.util.HashMap;
import java.util.Map;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import play.db.jpa.Model;

@Entity
public class FooSystem extends Model
{
    @ElementCollection
    private Map<Long, Foo> fooMap = new HashMap<Long, Foo>();

    public FooSystem()
    {
    }

    public Map<Long, Foo> getFooMap()
    {
        return fooMap;
    }

    public void put(Long l, Foo f)
    {
        fooMap.put(l, f);
    }
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7521218

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档