Обновление коллекции @OneToMany - PullRequest
0 голосов
/ 28 декабря 2011

Я пытаюсь сделать что-то вроде стены Facebook, но у меня есть проблема.

Моя база данных состоит всего из двух таблиц: одна для пользователей и одна для сообщений.В каждом сообщении есть ссылка на пользователя (внешний ключ к пользовательской таблице).

Я пытался заставить его работать, и все идет отлично, каждый пользователь может вставить свои собственные сообщения и увидеть сделанныйдругими, но функция вставки работает не так, как должна!

Когда я вставляю новое сообщение, оно корректно вставляется в базу данных, но просто не будет отображаться до следующего перезапуска сервера!Кажется, что сопоставленная коллекция постов не обновлена ​​правильно, поэтому бин вернет тот, который он нашел при первом запуске.

Вот код, используемый для сопоставления сущностей:

ПОЛЬЗОВАТЕЛЬ

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;

Как это исправить?

РЕДАКТИРОВАТЬ:

Вот управляемый компонент, который работает с сообщениями.Он вызывается страницей 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()); 

, а вот мой метод getPosts () для управляемого сообщения

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

Он должен делать именно то, что я говорил ранее, поэтомуЯ сохраняю имя пользователя (plain String) в сеансе, а затем вызываю метод 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 голосов
/ 28 декабря 2011

Когда вы получаете сообщение пользователя, вы получаете пользователя из сеанса.Таким образом, очевидно, что если некоторые сообщения были добавлены или удалены с момента сохранения пользователя в сеансе, вы их не увидите.

Не кэшируйте пользователя в сеансе, и все будет хорошо.Если пользователь должен где-то кэшироваться, он находится в кэше второго уровня Hibernate.

...