更新@OneToMany集合

时间:2011-12-27 22:35:42

标签: java-ee mapping ejb one-to-many

我正在尝试做类似Facebook的墙,但我遇到了问题。

我的数据库只有两个表,一个用于用户,一个用于帖子。 每个帖子都有对用户的引用(用户表的外键)。

我试图让它工作并且它很好,每个用户都可以插入自己的帖子并看到其他人制作的帖子,但插入功能不能正常工作!

当我插入一个新帖子时,它已正确插入数据库,但它只是在下一次服务器重启之前不会显示! 似乎映射的帖子集合没有正确更新,因此bean将返回他在第一次运行时找到的那个。

以下是用于映射实体的代码:

USER

public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id    
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 20)
@Column(name = "username")
private String username;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 45)
@Column(name = "password")
private String password;
@Basic(optional = false)
@NotNull
@Column(name = "regDate")
@Temporal(TemporalType.DATE)
private Date regDate;
@Basic(optional = false)
@NotNull
@Column(name = "id")
private int id;
@Column(name = "birthDate")
@Temporal(TemporalType.DATE)
private Date birthDate;
@Size(max = 255)
@Column(name = "avatar")
private String avatar;
@Size(max = 45)
@Column(name = "name")
private String name;
@Size(max = 45)
@Column(name = "surname")
private String surname;
@OneToMany(mappedBy="utente", fetch = FetchType.EAGER)
private Collection<Post> posts;

POST

public class Post implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@NotNull
@Column(name = "id")
private Integer id = 0;
@Basic(optional = false)
@NotNull
@Lob
@Size(min = 1, max = 65535)
@Column(name = "text")
private String text;
@Basic(optional = false)
@NotNull
@Column(name = "date")
@Temporal(TemporalType.DATE)
private Date date;
@Basic(optional = false)
@NotNull
@Column(name = "time")
@Temporal(TemporalType.TIME)
private Date time;
@JoinColumn(name = "user", referencedColumnName = "username")
@ManyToOne(fetch = FetchType.EAGER, optional = false)
private User user;

我该如何解决?

编辑:

这是与帖子一起使用的Managed Bean。它由JSF页面调用,该页面使用getPosts()填充dataTable,并使用表单插入帖子(postText是另一个具有getter和setter的属性)

@Named(value = "postsMB")
@RequestScoped
public class PostsMB {

@EJB
private UtenteFacadeLocal userFacade;
@EJB
private PostManagerLocal postManager;
protected String username;

/** Creates a new instance of PostsMB */
public PostsMB() {
}
protected List<Post> posts;

/**
 * Get the value of posts
 *
 * @return the value of posts
 */
public List<Post> getPosts() {
    //Let's see if we are trying to display posts from another user (passed with a GET param) or from the logged in user
    username = (String) FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("username");
    if (username != null && !username.isEmpty()) {
        user = userFacade.find(username);
    }
    if (user == null) {
        HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
        user = (Utente) session.getAttribute("user");
        if (user == null) {
            return null;
        }
    }
    //Once we've got the right user, we get all his posts
    posts = new LinkedList<Post>(user.getPosts());        
    return posts;
}
public void insertPost() {
    //We get the user from the session and we use it to insert the post
    user = (Utente) ((HttpSession) (FacesContext.getCurrentInstance().getExternalContext().getSession(false))).getAttribute("user");
    postManager.insertPost(postText, user);
}

这个托管Bean调用另一个Bean(PostManager),它只调用一个自动生成的PostFacade类,它将数据插入到数据库中。

@Stateless
public class PostManager implements PostManagerLocal {

@EJB
private PostFacadeLocal postFacade;

@Override
public void insertPost(Post post) {
    postFacade.create(post);        
}

@Override
public void insertPost(String text, User user) {
    Post p = new Post();
    p.setText(text);
    p.setUser(user);
    p.setDate(Calendar.getInstance().getTime());
    p.setTime(Calendar.getInstance().getTime());
    insertPost(p);
}

使用此类代码

中的代码重新发布帖子
@OneToMany(mappedBy="user", fetch = FetchType.EAGER)
private Collection<Post> posts;

public Collection<Post> getPosts() {        
    return posts;
}

public void setPosts(Collection<Post> posts) {
    this.posts = posts;
}

编辑2:

这是我的登录方法

User u = userManager.doLogin(username, password);
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);
        session.setAttribute("username", u.getUsername()); 

这是Posts Managed Bean的getPosts()方法

HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
        user = utenteFacade.find(session.getAttribute("username));   
posts = new LinkedList<Post>(user.getPosts());

它应该完全按照我之前说过的方式执行,因此我将用户名(plain String)存储到会话中,然后调用facade的find方法来获取用户的新实例。 怎么了?

编辑3:

UtenteFacade

@Stateless
public class UtenteFacade extends AbstractFacade<Utente> implements UtenteFacadeLocal {
@PersistenceContext(unitName = "LoginSession-ejbPU")
private EntityManager em;

@Override
protected EntityManager getEntityManager() {
    return em;
}

public UtenteFacade() {
    super(Utente.class);
}

}

AbstractFacade

public abstract class AbstractFacade<T> {
private Class<T> entityClass;

public AbstractFacade(Class<T> entityClass) {
    this.entityClass = entityClass;
}

protected abstract EntityManager getEntityManager();

public void create(T entity) {
    getEntityManager().persist(entity);
}

public void edit(T entity) {
    getEntityManager().merge(entity);
}

public void remove(T entity) {
    getEntityManager().remove(getEntityManager().merge(entity));
}

public T find(Object id) {
    return getEntityManager().find(entityClass, id);
}

public List<T> findAll() {
    javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
    cq.select(cq.from(entityClass));
    return getEntityManager().createQuery(cq).getResultList();
}

public List<T> findRange(int[] range) {
    javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
    cq.select(cq.from(entityClass));
    javax.persistence.Query q = getEntityManager().createQuery(cq);
    q.setMaxResults(range[1] - range[0]);
    q.setFirstResult(range[0]);
    return q.getResultList();
}

public int count() {
    javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
    javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
    cq.select(getEntityManager().getCriteriaBuilder().count(rt));
    javax.persistence.Query q = getEntityManager().createQuery(cq);
    return ((Long) q.getSingleResult()).intValue();
}

1 个答案:

答案 0 :(得分:0)

当您收到用户的帖子时,您将从会话中获得该用户。因此,很明显,如果您在会话中存储用户后添加或删除了某些帖子,您将看不到它们。

不要将用户缓存在会话中,一切都会好的。如果用户必须在某处缓存,则它位于Hibernate二级缓存中。