初始化惰性集合时出错

Error Initializing Lazy Collection

我正在尝试编写一些代码来确定客户是否具有某些功能。我有这个方法:

@Transactional(readOnly = true)
public boolean customerHasFeature(String customerId, String feature) {
    Customer customer = customerDAO.findByCid(customerId);
    if(customer != null) {
        return customer.hasFeatureNamed(feature);
    }

    return false;
}

customerDAO 方法在这里

@Transactional(readOnly = true)
public Customer findByCid(String cid) {
    List<Customer> customers = findByCriteriaImpl(Restrictions.eq("cid", cid));
    if(customers.size() > 0)
        return customers.get(0);
    return null;
}

在我检索客户后,在 customerHasFeature 中它没有加载功能,我收到错误

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.socialware.model.Customer.features, no session or session was closed

调试findbyCid时,可以看到criteria检索customer后加载的features,但是return customer到customerHasFeature时出错。

我尝试添加

Hibernate.initialize(customer.getFeatures());

在我调用 customerHasFeature 方法中的 customerDAO 之后,我得到了

org.hibernate.HibernateException: collection is not associated with any session

我正在使用 hibernate 3,感谢任何帮助或指导。

编辑

这是 findByCriteriaImpl 方法。

List<T> findByCriteriaImpl(Criterion... criterion) {
       Criteria crit = createCriteria(getPersistentClass());
       if (criterion != null) {
          for (Criterion c : criterion) {
               crit.add(c);
          }
       }
       long startTime = System.currentTimeMillis();
       List<T> toReturn = crit.list();
       reportQueryTimeForMonitoring(System.currentTimeMillis() - startTime, "findByCriteriaImpl", "for criteria " + crit);
       return toReturn;
}

和客户 class

public class Customer implements Serializable{
    private static final long serialVersionUID = -1L;

    @Field(index=Index.UN_TOKENIZED)
    private long customerId;

    private String cid;

    //@Field
    private String name;

    private Set<Feature> features;
    private boolean deleted = false;
    private String randomKey;

    public Customer() {
    }

    @Override
    public String toString() {
        return new StringBuilder()
            .append("Customer{")
            .append(customerId).append(", ")
            .append(cid).append(", ")
            .append(name).append(", ")
            .append(deleted)
            .append("}").toString();
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj)
            return true;
        if(obj == null)
            return false;
        if(getClass() != obj.getClass())
            return false;
        Customer other = (Customer) obj;
        if(cid == null) {
            if(other.cid != null)
                return false;
        }
        else if(!cid.equals(other.cid))
            return false;
        if(customerId != other.customerId)
            return false;
        if(name == null) {
            if(other.name != null)
                return false;
        }
        else if(!name.equals(other.name))
            return false;
        return true;
    }

    public long getCustomerId() {
        return customerId;
    }

    public void setCustomerId(long customerId) {
        this.customerId = customerId;
    }

    public void addFeature(Feature feature) {
        if(null == getFeatures()) {
            features = new HashSet<Feature>();
        }
        features.add(feature);
    }

    public Set<Feature> getFeatures() {
        return features;
    }

    public void setFeatures(Set<Feature> features) {
        this.features = features;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCid() {
        return cid;
    }

    public void setCid(String cid) {
        this.cid = cid;
    }

    public boolean isDeleted() {
        return deleted;
    }

    public void setDeleted(boolean deleted) {
        this.deleted = deleted;
    }

    public String getRandomKey() {
        return randomKey;
    }

    public void setRandomKey(String randomKey) {
        this.randomKey = randomKey;
    }

    public boolean hasFeatureNamed(String name) {
        Set<Feature> features = getFeatures();

        if (features == null) {
            return false;
        }
        for (Feature feature : features) {
            if (feature != null && feature.getName().equals(name)) {
                return true;
            }
        }
        return false;
    }

    public void removeFeature(String name) {
        Set<Feature> features = getFeatures();

        if (features == null) {
            return;
        }
        for (Iterator<Feature> i = features.iterator(); i.hasNext();) {
            Feature feature = i.next();
            if (feature.getName().equals(name)) {
                i.remove();
            }
        }
    }
}

查看您的 Customer class,我看不出您是如何映射 features 集合的,但请注意,无论您如何映射,默认的抓取类型都是 LAZY,意味着你的集合不会在读取过程中被初始化。

请尝试以下操作:

List<T> findByCriteriaImpl(List<String> fetches, Criterion... criterion) {
       Criteria crit = createCriteria(getPersistentClass());
       if (criterion != null) {
          for (Criterion c : criterion) {
               crit.add(c);
          }
          for (String s : fetches) {
               crit.setFetchMode(s, FetchMode.JOIN);
          }
       }
       long startTime = System.currentTimeMillis();
       List<T> toReturn = crit.list();
       reportQueryTimeForMonitoring(System.currentTimeMillis() - startTime, "findByCriteriaImpl", "for criteria " + crit);
       return toReturn;
}

并像这样调用 findByCriteriaImpl

List<Customer> customers = findByCriteriaImpl(Collections.asList("features"), Restrictions.eq("cid", cid));

这样您就可以告诉您的方法您想要将哪些集合与您的实体一起获取。