【问题标题】:PersistenceException, Column 'id' specified twicePersistenceException,列“id”指定了两次
【发布时间】:2014-06-24 02:32:35
【问题描述】:

我在 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;
}

为了简洁起见,我已经从这些模型中排除了一些 setter 和 getter,所以它不会阻塞这篇文章。

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

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

【问题讨论】:

  • 看起来您引用了 Comment 上定义的 Blog 实体。不要同时定义外键的列映射。只是实体引用 - 考虑对象而不是表/FK。
  • 评论对象上没有到博客的列映射。除非您指的是 Blog 类中定义的列映射,否则无论我删除任何一个,它仍然会引发相同的错误。

标签: java database jpa playframework-2.0 ebean


【解决方案1】:

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

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

@ManyToOne
public Blog blog;

“博客”字段的默认列名是:blog_id 但是,您已经将“blog_id”列命名为该列。 有趣的是,创建此表时不会引发错误/警告...

所以当你调用comment.save()时,会生成如下插入语句:

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

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

要解决此问题,只需为您的“博客”属性指定一个不同的名称以用于外键列:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    只是总结问题:

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

    博客ID

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

    当尝试加入该字段上的列时,它总是会失败,因为它创建了这个 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;
    

    希望这会有所帮助! =)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-03
      • 1970-01-01
      • 2019-09-23
      相关资源
      最近更新 更多