有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

传递给持久化的java分离实体以在JPA中进行批插入

对于下面的批插入方法,我得到这个异常“分离的实体传递到persist”。你能看看这个方法并给我一些提示吗

非常感谢你

如果需要,我将在这里提供实体,目前我提供关键字实体

public class Keyword implements Serializable {


    private static final long serialVersionUID = -1429681347817644570L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="key_id")
    private long keyId;   

    @Column(name="key_name")
    private String keyName;   

    @ManyToOne 
    @JoinColumn(name="tweet_id")
     private Tweet tweet;


    public long getKeyId() {
        return keyId;
    }


    public void setKeyId(long keyId) {
        this.keyId = keyId;
    }

    public String getKeyName() {
        return keyName;
    }

    public void setKeyName(String keyName) {
        this.keyName = keyName;
    }


    public Tweet getTweet() {
        return tweet;
    }

    public void setTweet(Tweet tweet) {
        this.tweet = tweet;
    }

}

此处推特实体:

@Entity
@Table(name="tweets")

public class Tweet implements Serializable{

    @Id
    @Column(name="tweet_id")
    private long tweetId;

    @Column(name="tweet_text")
    private String tweetText;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created_at")
    private Date createdAt;

    @Column(name="lang_code")
    private String languageCode;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;


    @OneToMany(mappedBy="tweet")
    //@JoinColumn(name="hashtag_id")
    private List<Hashtag> hashtags;


    @OneToMany(mappedBy="tweet")
    //@JoinColumn(name="url_id")
    private List<Url> urls;


    public List<Keyword> getKeywords() {
        return keywords;
    }


    public void setKeywords(List<Keyword> keywords) {
        this.keywords = keywords;
    }


    @OneToMany(mappedBy="tweet")
    //@JoinColumn(name="url_id")
    private List<Keyword> keywords;




    public long getTweetId() {
        return tweetId;
    }


    public void setTweetId(long tweetId) {
        this.tweetId = tweetId;
    }


    public String getTweetText() {
        return tweetText;
    }


    public void setTweetText(String tweetText) {
        this.tweetText = tweetText;
    }


    public Date getCreatedAt() {
        return createdAt;
    }


    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }


    public String getLanguageCode() {
        return languageCode;
    }


    public void setLanguageCode(String languageCode) {
        this.languageCode = languageCode;
    }


    public User getUser() {
        return user;
    }


    public void setUser(User user) {
        this.user = user;
    }


    public List<Hashtag> getHashtags() {
        return hashtags;
    }


    public void setHashtags(List<Hashtag> hashtags) {
        this.hashtags = hashtags;
    }


    public List<Url> getUrls() {
        return urls;
    }


    public void setUrls(List<Url> urls) {
        this.urls = urls;
    }


    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (int) (tweetId ^ (tweetId >>> 32));
        return result;
    }


    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Tweet other = (Tweet) obj;
        if (tweetId != other.tweetId)
            return false;
        return true;
    }

这里是Url实体:

@Entity
@Table(name="tweet_url")
public class Url implements Serializable{


    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="url_id")
    private int urlId;


    @Column(name="url")
    private String url;

    @ManyToOne
    @JoinColumn(name="tweet_id",referencedColumnName="tweet_id")
    private Tweet tweet;

    public int getUrlId() {
        return urlId;
    }

    public void setUrlId(int urlId) {
        this.urlId = urlId;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Tweet getTweet() {
        return tweet;
    }

    public void setTweet(Tweet tweet) {
        this.tweet = tweet;
    }

下面是标签实体:

@Entity
@Table(name="tweet_hashtag")
public class Hashtag implements Serializable{


    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="hashtag_id")
    private int hashtagId;


    @Column(name="hashtag")
    private String hashtag;

    @ManyToOne
    @JoinColumn(name="tweet_id",referencedColumnName="tweet_id")
    private Tweet tweet;

    public int getHashtagId() {
        return hashtagId;
    }

    public void setHashtagId(int hashtagId) {
        this.hashtagId = hashtagId;
    }

    public String getHashtag() {
        return hashtag;
    }

    public void setHashtag(String hashtag) {
        this.hashtag = hashtag;
    }

    public Tweet getTweet() {
        return tweet;
    }

    public void setTweet(Tweet tweet) {
        this.tweet = tweet;
    }

以及方法

public  void batchInsert(List<Keyword> results) throws HibernateException {

    // chekeywordck if key exists

    //  try {
    em=RunQuery.emf.createEntityManager();
    em.getTransaction().begin();

    for(Keyword result:results)
    {

        try{
        em.persist(result.getTweet().getUser());
        }
        catch(ConstraintViolationException ce)
        {
            System.out.print("duplicated insert catched");

        }

        try{
        em.persist(result.getTweet());
        }
        catch(ConstraintViolationException ce)
        {
        System.out.print("duplicated insert catched");
        }

        if(result.getTweet().getHashtags()!=null)
            for(Hashtag hashtag:result.getTweet().getHashtags())
                   em.persist(hashtag);

        if(result.getTweet().getUrls()!=null)
            for(Url url:result.getTweet().getUrls())
                em.persist(url);

       em.persist(result);

        em.flush();
        em.clear();

      //when I put these two line out of this loop, it still is the same. 
    }
    em.getTransaction().commit();


       // } 


}

这里有一个例外:

Exception in thread "Thread-3" javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: model.twitter.entities.Url
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1187)
    at model.service.QueryResultService.batchInsert(QueryResultService.java:74)
    at controller.ResultsController.save(ResultsController.java:125)
    at controller.ResultsController.parse(ResultsController.java:89)
    at main.TwitterStreamConsumer.run(TwitterStreamConsumer.java:41)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: model.twitter.entities.Url
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:139)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
    ... 5 more

共 (2) 个答案

  1. # 1 楼答案

    对于所有持久化调用,请尝试改用以下方法:

    if(result.getTweet().getUser().getId() == null) {
        em.persist(result.getTweet().getUser());
    } else {
        result.getTweet().setUser(em.merge(result.getTweet().getUser()));
    }
    
    if(result.getTweet().getId() == null) {
        em.persist(result.getTweet());
    } else {
        result.setTweet(em.merge(result.getTweet()));
    }
    
    if(result.getId() == null) {
        em.persist(result);
    } else {
        result = em.merge(result);
    }
    
  2. # 2 楼答案

    回答您的问题:您的模型定义了Tweet和URL之间的一对多关系,没有任何级联关系。当您传递一个Tweet实例进行持久化时,URL对象尚未保存,并且您的模型没有强制Tweet将持久化操作级联到URL实例。因此,它无法与他们建立关系。 级联告诉hibernate如何在相关实体上执行DB操作。 您可以指示它将持久化操作传递/级联到相关实体,级联所有操作或操作数组

    也就是说,如果您修改与级联信息的关系,您的问题(其中1个)可以得到解决:

     @OneToMany(mappedBy="tweet", cascade={CascadeType.PERSIST})
     private List<Url> urls;
    

    但您的示例指出了其他可能的问题,我鼓励您花更多的时间阅读Hibernate ORM文档,并在关系较少的示例模型上进行练习

    其中一个明显的问题似乎是缺乏对关系所有者概念的理解。 例如,在Tweet-to-Url关系中,Url是关系所有者(负责管理关系,例如通过外键管理链接) 更多信息,请咨询hibernate docs或数百个类似问题here on SO中的一个。 根据填充数据的方式,您可能会遇到约束问题,或者您的实体不会链接在一起,因为您没有保存所属方。 另外,使用try/catch来检测约束冲突是检测重复条目的一种非常糟糕的方法。ConstraintViolationException可能有许多原因,您获取它们的原因与上述关系映射问题有关。 ORM是一门复杂的学科,从较小的例子开始,在转向更具挑战性的模型之前,尝试理解框架机制,这确实是有益的。祝你好运