PersistenceException,列'id'指定两次

时间:2014-06-24 02:32:36

标签: java database jpa playframework-2.0 ebean

我在Play Framework 2.2.3中有以下文件

控制器:

public class Comment extends Controller
{
    public Result create(UUID id)
    {
        models.blog.Blog blog = models.blog.Blog.finder.byId(id);

        Result result;

        if(blog == null)
        {
            result = notFound(main.render("404", error404.render()));
        }
        else
        {
            Form<models.blog.Comment> commentForm = Form.form(models.blog.Comment.class);
            commentForm = commentForm.bindFromRequest();

            if(commentForm.hasErrors())
            {
                result = badRequest(Json.toJson(commentForm));
            }
            else
            {
                models.blog.Comment comment = commentForm.get();

                comment.setId(UUID.randomUUID());
                comment.setTimeCreated(new Date());
                comment.setBlogId(blog.getId());

                comment.save();

                result = ok(Json.toJson(comment));
            }
        }

        return result;
    }
}

两个模特

@Entity
@Table(name="blog")
public class Blog extends Model
{
    private static final SimpleDateFormat MONTH_LITERAL = new SimpleDateFormat("MMMMM"),
                                          DAY_NUMBER = new SimpleDateFormat("d"),
                                          YEAR_NUMBER = new SimpleDateFormat("yyyy");
    public static Finder<UUID, Blog> finder = new Finder<UUID, Blog>(UUID.class, Blog.class);

    @Id
    @Column(name="id",length=36, nullable=false)
    public UUID id;

    @OneToOne
    @JoinColumn(name="author_id")
    public User author;

    @Column(name="title",length=255)
    public String title;

    @Column(name="summary",length=255)
    public String summary;

    @Column(name="url",length=255)
    public String url;

    @Column(name="content")
    public String content;

    @Column(name="time_updated")
    public Date time_created;

    @Column(name="time_created", nullable=false)
    public Date time_updated;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name="blog_id")
    public List<Comment> comments;

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(
    name="blog_tag_map",
    joinColumns={ @JoinColumn(name="blog_id", referencedColumnName="id") },
    inverseJoinColumns={ @JoinColumn(name="tag_id", referencedColumnName="id") }
)
    public List<Tag> tags;

    public List<Comment> getComments()
    {
        return this.comments;
    }
}

@Entity
@Table(name="blog_comment")
public class Comment extends Model
{
    private static final SimpleDateFormat MONTH_LITERAL = new SimpleDateFormat("MMMMM"),
                                          DAY_NUMBER = new SimpleDateFormat("d"),
                                          YEAR_NUMBER = new SimpleDateFormat("yyyy");

    @Id
    @Column(name="id",length=36, nullable=false)
    public UUID id;

    @Column(name="blog_id", length=36)
    public UUID blog_id;

    @ManyToOne
    public Blog blog;

    @Column(name="content", length=500)
    public String content;

    @Column(name="website", length=255)
    public String website;

    @Column(name="name", length=255)
    public String name;

    @Column(name="time_created", updatable=false)
    public Date time_created;
}

为了简洁起见,我已经从这些模型中排除了一些限制器和吸气剂,所以它不会堵塞这篇文章。

当我尝试向上述控制器发出POST请求时,一切正常,直到我到达控制器文件中的“comment.save()”语句,然后我收到以下错误。

enter image description here

我不确定为什么这个保存没有通过,以及为什么存在列冲突。 非常感谢

2 个答案:

答案 0 :(得分:5)

问题在于您在评论的实体中基本上为Blog定义了两个外键列:

@Column(name = "blog_id", length = 36)
public UUID blog_id;

@ManyToOne
public Blog blog;

您博客的默认列名称&#39;字段是:blog_id 但是,您已经将自己命名为blog_id&#39;专栏。 有趣的是,创建此表时不会引发错误/警告......

因此,当您调用comment.save()时,将生成以下insert语句:

insert into blog_comment (id, blog_id, content, website, name, time_created, blog_id) values (?,?,?,?,?,?,?)

请注意对&#39; blog_id&#39;的引用列两次,这是无效的。 这是因为上面的双重映射。

要修复,只需提供您的博客&#39;属性是用于外键列的其他名称:

@Column(name = "blog_id", length = 36)
public UUID blog_id;

@ManyToOne
@JoinColumn(name = "blogId")
public Blog blog;

我不确定您为什么要像这样映射您的实体(可能是旧版架构?),但是&#39; blog_id&#39;字段似乎是多余的(并且令人困惑),因为您已经以“博客”形式存在实体映射。属性。

答案 1 :(得分:1)

这个问题很老了,但是对于将来的参考,我发现这个答案解决了my problem

在网络上的众多搜索者之后,我找到了这个答案here - 感谢jtal!

只是总结一下问题:

使用Ebean我做了一个@ManyToOne实体,无论如何都没有在数据库中实现, 甚至更多的是连接字段,在你的情况下

  

blogId

是一个有效值的有效字段。

当尝试加入该字段上的列时,它将始终失败,因为它会创建此sql查询:

SELECT 
*
FROM
    blog_comment;

select 
    t0.id c0, 
    t0.blog_id c1, 
    t0.content c2, 
    t0.website c3, 
    t0.time_created c4, 
    t0.blog_id c5 <---- notice this duplicate
from 
    blog_comment t0 

为了解决这个问题,我告诉ebean 不要使用第二组属性

你的新ebean元素应该是这样的:

@ManyToOne
@JoinColumn(name = "blogId", insertable = false, updatable = false)
public Blog blog;

希望这有帮助! =)