更新 @OneToMany 集合

发布于 2024-12-23 03:02:45 字数 6976 浏览 3 评论 0原文

我正在尝试做一些像 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;

我该如何解决这个问题?

编辑:

这是与帖子一起使用的托管 Bean。它由 JSF 页面调用,该页面使用 getPosts() 填充数据表和表单来插入帖子(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);
}

帖子是用 User 类中的代码检索的

@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());

它应该完全按照我之前所说的操作,所以我将用户名(纯字符串)存储到session,然后我调用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();
}

I'm trying to do something like Facebook's wall but I've got a problem.

My DB is made by just two tables, one for the users and one for the posts.
Each post has a reference to the user (a foreign key to the user table).

I've tried to make it work and it goes quite fine, each user can insert his own posts and see the one made by the others, but the insert feature isn't working like it should!

When I insert a new post, it's inserted correctly into the database, but it simply won't show until the next server restart !
It seems that the mapped collection of posts isn't correctly updated, so the bean will return the one that he found at the first run.

Here's the code used to map the entities :

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;

How can I fix that ?

EDIT :

Here's the Managed Bean that works with the posts. It's called by a JSF page that uses getPosts() to fill a dataTable and a form to insert the post (postText is another property that has getter and 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);
}

This managed Bean calls another Bean (PostManager) that simply calls an auto-generated PostFacade class which inserts the data into the DB.

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

Posts are retrived with this code in User class

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

EDIT 2 :

Here's my login method

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

and here's my getPosts() method of the Posts Managed Bean

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

It should do exactly what I've said before, so I store the username(plain String) into a session and then I call the facade's find method to get a new instance of the user.
What's wrong?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

为人所爱 2024-12-30 03:02:45

当您获取用户的帖子时,您就从会话中获取了该用户。因此,显然,如果自您将用户存储在会话中以来添加或删除了某些帖子,您将看不到它们。

不要在会话中缓存用户,一切都会好起来的。如果用户必须缓存在某个地方,那就是 Hibernate 二级缓存。

When you get the user's post, you get the user from the session. So, obviously, if some posts have been added or removed since you stored the user in the session, you won't see them.

Don't cache the user in the session, and everything will be fine. If the user must be cached somewhere, it's in the Hibernate second-level cache.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文