如何使用JPA将Map(java.util.Map)对象持久保存在实体中并确保持久性级联?

发布于 2021-02-01 12:41:00

我最近开始玩Play!Java框架1.2.3版(最新)。在测试框架时,尝试Map在名为的Hibernate实体中保留对象时遇到了一个奇怪的问题FooSystem。地图对象映射长到Hibernate的实体,我呼吁Foo,随着申报Map<Long, Foo> fooMap;

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

这是我用于实体的代码。首先是Foo

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

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我用来测试设置的课程:

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表中,这是理想的结果。我该怎么办?我想念什么?

关注者
0
被浏览
99
1 个回答
  • 面试哥
    面试哥 2021-02-01
    为面试而生,有面试问题,就找面试哥。

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

    在上面发布的代码中,您可以在FooSystem构造函数中看到在持久化对象之前已放入两个Foo对象f1和。我意识到,如果将它放入地图中时不在数据库中,那么JPA如何将其ID用作联接表中的外键?f2``fooMap``Foo``f1

    如果您可以看到我要使用的这种推理方法,那么您会发现显而易见的答案是,JPA 无法
    完成使用外键引用不存在的键这一惊人的壮举。奇怪的是那出戏!控制台根本没有记录我发布的原始代码的任何错误,即使它根本不正确。要么框架吞噬了Exception在此过程中抛出的所有错误,要么是我编写了
    应该 产生的代码Exception

    因此,为解决此问题,我在对Foo实体执行任何操作之前将其保留下来。然后才把它们放进去fooMap。最后,一旦fooMap填充完毕,我便保留了该FooSystem实体。

    这是更正后的TestController类:

    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,因此这是该类的最终代码:

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


推荐阅读
知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看