【问题标题】:JPA - How to avoid getting an empty list?JPA - 如何避免得到一个空列表?
【发布时间】:2011-10-29 16:57:45
【问题描述】:

我正在创建一个社交网站,比如 Facebook,作为一个大学项目。用户可以上传照片,但我无法检索特定用户的照片列表。

这是我现在的做法:

@Entity
@Table(name = "users")
public class User implements Serializable {

@Id
private String emailAddress;
private String password;
private String firstName;
private String lastName;

(...)

@OneToMany(mappedBy = "owner", fetch = FetchType.EAGER)
private List<Photo> photos;

public User() {
}

(...)

public void addPhoto( Photo photo){
    photos.add(photo);
}

public List<Photo> getPhotos() {
    return photos;
}
}

这是 Photo 实体:

@Entity
public class Photo implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String url;
private String label;     
@ManyToOne
private User owner;

public Photo() {
}

(...)

public User getOwner() {
    return owner;
}    
}

每张照片都是通过创建包含它的帖子上传的。这是执行此操作的 EJB:

@Stateless
public class PublicPost implements PublicPostRemote {

@PersistenceContext
EntityManager em;

@Override
public void createPost(LoginUserRemote loginUserBean, String targetEmail, final String content, final String photoURL) {
    if (loginUserBean.isLoggedIn()) {
        final User author = loginUserBean.getLoggedUser();
        System.out.println(targetEmail);
        final User target = em.find(User.class, targetEmail);
        if (author != null && target != null) {
            //See if there's a photo to post as well
            Photo photo = null;
            if (photoURL != null) {
                photo = new Photo(photoURL, author, content);
                em.persist(photo);
            }

            MessageBoard publicMessageBoard = target.getPublicMessageBoard();
            Post post = new Post(author, content);
            post.setMessageBoard(publicMessageBoard);
            if (photo != null) {
                post.setPostPhoto(photo);
            }
            em.persist(post);
            em.refresh(publicMessageBoard);
            //Send an e-mail to the target (if the author and the target are different)
            if (!author.getEmailAddress().equals(target.getEmailAddress())) {
                final String subject = "[PhaseBook] " + author.getEmailAddress() + " has posted on your public message board.";
                Thread mailThread = new Thread() {

                    @Override
                    public void run() {
                        try {
                            GMailSender.sendMessage(target.getEmailAddress(), subject, content);
                        } catch (MessagingException ex) {
                            Logger.getLogger(PublicPost.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                };
                mailThread.start();
            }
        }
    }
}
}

所以发生的事情是:我创建了一个包含照片的新帖子,但后来,当我在网络层使用它时...

LoginUserRemote lur = (LoginUserRemote)session.getAttribute("loginUserBean");
User user = lur.getLoggedUser();
List<Photo> photos = user.getPhotos();
System.out.println();
System.out.println("This user has this many photos: " + photos.size());

...它总是告诉我用户有 0 张照片。为什么是这样?我是否错误地定义了用户和照片之间的关系?我是否忘记坚持/刷新任何东西?还是问题出在其他地方?

【问题讨论】:

    标签: list jpa ejb


    【解决方案1】:

    如果您在 HTTP 会话中存储一个分离的用户对象(登录的用户),然后创建并保存以该分离用户为所有者的照片,JPA 不会自动将照片添加到分离的用户。对于实体管理器,这个分离的用户不存在:它不再由它负责。

    即使 User 仍处于附加状态,您也有责任保持对象图的连贯性。如果您修改了关联的一侧(通过将用户设置为照片的所有者),您还应该修改另一侧(通过将照片添加到所有者的照片列表中)。

    我不确定这是问题的原因,因为您没有向我们展示 loginUserBean 是什么以及为获取登录用户所做的工作,但它可能是答案。

    【讨论】:

      【解决方案2】:

      这里有一系列问题:

      • 照片是否真的存储在数据库中?也许您没有打开交易?

      • 您没有更新关联的双方。

      理论上你只需要更新拥有方,但最好是安全而不是抱歉:

      photo = new Photo(photoURL, author, content);
      em.persist(photo);
      author.addPhoto(photo);
      
      • 您正在从会话中获取用户,然后检索相关的照片集合。你真的知道这意味着什么吗?如果用户有数百张照片,您真的想一直将它们与用户一起存储在 HTTP 会话中吗?这不是 Facebook 的工作方式;-)。

      认为刷新您的实体(使用em.refresh(lur.getLoggedUser()))可能有效,但仅限于大学,而不是现实生活。一次将所有用户照片加载到内存中是一种矫枉过正的做法。就我个人而言,我什至会从用户中删除 photos 关联以避免这种情况。一次加载一页,并且仅按需加载。

        1234563其中。所以添加照片并不意味着photos 集合会在每个对象中神奇地更新。我仔细想想,这会更糟。
      • 最后但同样重要的是,您的createPost() 确实需要一些代码审查。它一次至少做 4 件事,System.out,一次按需创建线程,当不满足先决条件时(如用户未登录、缺少参数)默默地什么都不做,混合不同抽象级别的关注。不想太一丝不苟,但你的成绩可能会受到代码质量的影响。

      【讨论】:

        猜你喜欢
        • 2023-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-02
        • 2020-11-01
        • 1970-01-01
        • 2016-09-12
        相关资源
        最近更新 更多