如何使用 JPA 在实体内持久化 Map (java.util.Map) 对象并确保持久性级联? [英] How do I use JPA to persist a Map (java.util.Map) object inside an entity and ensure the persistence cascades?

查看:23
本文介绍了如何使用 JPA 在实体内持久化 Map (java.util.Map) 对象并确保持久性级联?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近开始玩 Play!Java 框架,版本 1.2.3(最新).在测试框架时,我在尝试将 Map 对象持久化到名为 FooSystem 的 Hibernate 实体中时遇到了一个奇怪的问题.Map 对象将 long 映射到我称为 Foo 的 Hibernate 实体,声明为 MapfooMap;

I have recently started playing around with the Play! Framework for Java, version 1.2.3 (the latest). While testing out the framework, I came across a strange problem when trying to persist a Map object inside a Hibernate entity called FooSystem. The Map object maps a long to a Hibernate entity I have called Foo, with the declaration Map<Long, Foo> fooMap;

我的问题如下:正确的表格已创建,因为我已经对它们进行了注释.但是,当FooSystem对象fs被持久化时,fs.fooMap中的数据不是!

My problem is as follows: The correct tables are created as I have annotated them. However, when the FooSystem object fs is persisted, the data in fs.fooMap is not!

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

Here is the code I am using for the entities. First is 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 类:

Here is the Controller class I am using to test my set-up:

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 表中,这是期望的结果.我该怎么办?我错过了什么?

The Play! framework automatically created a transaction for the HTTP request. Although data is inserted into the foo and foosystem tables, nothing is ever inserted into the foomap table, which is the desired result. What can I do about this? What am I missing?

推荐答案

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

I managed to solve this problem using the advice of Java Ka Baby. The issue was actually not in my Model classes; the problem lay within the Controller. Specifically, I was saving the entities in the wrong order. Once I realized that using the @ElementCollection annotation on the Map<Long, Foo> produced the same effects as the join table I was manually specifying, I tried I thought experiment where I re-thought how I was saving my entities.

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

In the code I posted above, you can see in the FooSystem constructor that two Foo objects, f1 and f2, are put into fooMap before the Foo objects are persisted. I realized that if f1 is not in the database when it is put into the map, how is JPA able to use its ID as a foreign key in the join table?

如果你能看出我的推理思路,你会发现显而易见的答案是 JPA 不能完成使用外键引用的惊人壮举一个不存在的键.奇怪的是,播放!控制台根本没有注意到我发布的原始代码有任何错误,即使它根本不正确.要么框架吞下了在此过程中抛出的每个 Exception,要么我编写了应该产生 Exception 的代码.

If you can see where I'm going with this line of reasoning, you can see that the obvious answer is that JPA is not able to accomplish this amazing feat of using a foreign key to reference a nonexistent key. The bizarre thing is that the Play! console did not note any errors at all for the original code I posted, even though it was not correct at all. Either the framework swallowed every Exception thrown during the process, or I've written code that should produce an Exception.

所以为了解决这个问题,我在对 Foo 实体执行任何操作之前保留了它们.直到那时我才将它们放入fooMap.最后,一旦 fooMap 被填充,我就保留了 FooSystem 实体.

So to fix the problem, I persisted the Foo entities before any operations were performed on them. Only then did I put them into fooMap. Finally, once fooMap was populated, I persisted the FooSystem entity.

这是更正后的 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,这是该类的最终代码:

And, since I changed FooSystem, here is the final code for that class:

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

这篇关于如何使用 JPA 在实体内持久化 Map (java.util.Map) 对象并确保持久性级联?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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