【问题标题】:Fetch a list in a @OneToMany association?在@OneToMany 关联中获取列表?
【发布时间】:2013-04-14 20:56:24
【问题描述】:

问题是,一个user 有一个或多个properties,所以这就是我的实体类user 的原因

@Entity
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

        // others attributes  

    //bi-directional many-to-one association to Property
    @OneToMany(mappedBy="user", fetch=FetchType.EAGER)
    private List<Property> properties;
    ..
}

我的实体property

@Entity
public class Property implements Serializable {
  private static final long serialVersionUID = 1L;
  ..
  //bi-directional many-to-one association to User
  @ManyToOne
  @JoinColumn(name="id_user")
  private User user;
  ..
}

这些实体由EclipseLink 生成。

这是我的桌子,我认为可以满足我的需求。

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
   ..
   PRIMARY KEY (`id`),
  UNIQUE KEY `email_UNIQUE` (`email`),
  KEY `u_id_city_to_ac_id_idx` (`id_city`),
  KEY `u_id_state_to_as_id_idx` (`id_state`),
  KEY `u_id_country_to_acy_id_idx` (`id_country`),
  CONSTRAINT `u_id_city_to_ac_id` FOREIGN KEY (`id_city`) REFERENCES `address_city` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `u_id_country_to_acy_id` FOREIGN KEY (`id_country`) REFERENCES `address_country` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `u_id_state_to_as_id` FOREIGN KEY (`id_state`) REFERENCES `address_state` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8 COMMENT='an user can be a tenant and a landlord also';

还有我的property 表:

CREATE TABLE `property` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `id_user` int(11) unsigned NOT NULL,
   ..
    PRIMARY KEY (`id`),
  KEY `p_id_accomodation_to_pac_id_idx` (`id_accomodation`),
  KEY `p_id_room_type_to_prt_id_idx` (`id_room_type`),
  KEY `p_id_bed_type_to_pbt_id_idx` (`id_bed_type`),
  KEY `p_id_policty_cancelation_to_pc_id_idx` (`id_policy_cancelation`),
  KEY `p_id_user_to_u_id_idx` (`id_user`),
  KEY `p_id_city_to_ac_id_idx` (`id_city`),
  KEY `p_id_state_to_as_id_idx` (`id_state`),
  KEY `p_id_country_to_acy_id_idx` (`id_country`),
  CONSTRAINT `p_id_accomodation_to_pac_id` FOREIGN KEY (`id_accomodation`) REFERENCES `property_accomodation` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `p_id_bed_type_to_pbt_id` FOREIGN KEY (`id_bed_type`) REFERENCES `property_bed_type` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `p_id_city_to_ac_id` FOREIGN KEY (`id_city`) REFERENCES `address_city` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `p_id_country_to_acy_id` FOREIGN KEY (`id_country`) REFERENCES `address_country` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `p_id_policty_cancelation_to_pc_id` FOREIGN KEY (`id_policy_cancelation`) REFERENCES `policy_cancellation` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `p_id_room_type_to_prt_id` FOREIGN KEY (`id_room_type`) REFERENCES `property_room_type` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `p_id_state_to_as_id` FOREIGN KEY (`id_state`) REFERENCES `address_state` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `p_id_user_to_u_id` FOREIGN KEY (`id_user`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

例如,我想在登录操作中获取 user 中的所有 properties

user = userEAO.find(user.getEmail());
user.getProperties(); //always empty

我该怎么做?我认为放置哪种类型的fetching 就足够了,但似乎不是。

更新 我换成LAZY我的FetchType,现在看:

//与属性的双向多对一关联 @OneToMany(mappedBy="user", fetch=FetchType.LAZY) 私有列表属性;

user登录系统时:

User u = userEAO.findByEmail(profile.getEmail());
if (u != null){
  if (u.getProperties() != null){
    u.getProperties().size();
    System.out.println(u.getProperties().size()); // now prints 1
}

James,在为user 创建一个新的property 时,您的意思是,refreshing 对象property,对吗?是的,在创建这个property 之后,我将它添加到user 列表properties =]

public Message create(Property property) {
        try{
            em.persist(property);
            em.flush();
            em.refresh(property);
        }catch(ConstraintViolationException cve){
            cve.printStackTrace();

        }catch (Exception e) {
            e.printStackTrace();
            // 1062 : duplicate entry
            if (e.getMessage().contains("Duplicate"))
                return new Message(-1000);
            else{
                e.printStackTrace();
                return new Message(-1);
            }
        }
        return new Message(0);
    }

【问题讨论】:

  • 没有必要为你的标题添加标签,有一个标签系统。请阅读meta.stackexchange.com/q/19190/147072 了解更多信息。
  • @Patrick,抱歉,感谢您提供的信息。
  • 尝试刷新实体,然后访问集合。如果这样可行,则意味着您没有维护双向关系的双方,这会破坏缓存。

标签: database jpa relational-database jpa-2.0 eclipselink


【解决方案1】:

FetchType.EAGER 表示您的Property 列表将与对象同时被检索。 LAZY 表示只要您调用getProperties().anyMethod(),就会检索您的列表。但是,条件是您的 User 对象仍由 JPA 管理(意味着它当前存在管理您的实体实例的 EntityManager 实例)。

eager 的兴趣在于,即使 EntityManager 已关闭(例如,您的基础交易已关闭),您也可以访问您的列表。一种懒惰的做法是,在有效使用对象之前,您不会执行查询并在内存中映射对象

因此,在您的情况下,如果列表为空,则与获取模式无关(您在检索到用户后立即显式调用 getProperties()),但这是因为您在 DB 中没有数据,或者您的映射。

【讨论】:

  • 实际上,只要调用 getProperties() 返回的列表中的方法,就会发生延迟加载。只是调用 getProperties() 不会触发延迟加载。
  • @Gab,我用我的关系和表格更新了我的帖子,你认为那里可能有什么问题?
  • @JBNizet,例如,我应该使用getProperties.get(0) 来加载我的properties 吗?
  • 是的,他是对的,我忘记了。您正在使用调试器查看它,不是吗? getSize() 也可以完成这项工作
  • 对不起老兄,我在调试代码时遇到了一些问题stackoverflow.com/questions/16006027/…,但我会马上看到你的方法。
【解决方案2】:

确保当你持久化你的用户对象时,你设置的是属性。当您保留一个新属性时,请确保您设置其用户并将该属性添加到用户的属性中。您需要保持双向关系的双方。

您也可以尝试执行 refresh()。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-19
    • 2021-12-11
    • 2018-03-23
    • 1970-01-01
    • 1970-01-01
    • 2014-05-01
    • 2010-10-08
    相关资源
    最近更新 更多