【问题标题】:JPA Eclipselink JOIN FETCH LAZY relation returning nullJPA Eclipselink JOIN FETCH LAZY 关系返回 null
【发布时间】:2014-03-26 22:20:07
【问题描述】:

我总是从我的 JPA 查询中的 JOIN FETCH 子句中得到 NULL,即使我已经按预期配置了所有内容:

@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
@Entity
@Table(name = "TB_BANNER_IMAGE")
public class BannerImage extends BaseEntity<Integer> {      
    protected FileReference fileReference;
    private String type;
    private String labelTitle;  

    protected BannerImage() {}

    @Id    
    @TableGenerator(name="genBannerImage", table="TB_ID_GENERATOR",
            pkColumnName="ID_NAME", valueColumnName="ID_VAL",
            pkColumnValue="TB_BANNER_IMAGE", allocationSize=1)
    @GeneratedValue(strategy=GenerationType.TABLE, generator="genBannerImage")
    @Column(name = "ID_BANNER_IMAGE", unique = true, nullable = false)
    public Integer getId() {
        return super.getId();
    }

    @Override
    public void setId(Integer id) {
        super.setId(id);
    }

    @Column(name="TYPE")
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="ID_FILE_REFERENCE", nullable=false)
    public FileReference getFileReference() {
        return fileReference;
    }

    public void setFileReference(FileReference fileReference) {
        this.fileReference = fileReference;
    }

    @Column(name="LABEL_TITLE")
    public String getLabelTitle() {
        return labelTitle;
    }

    public void setLabelTitle(String labelTitle) {
        this.labelTitle = labelTitle;
    }
}

对于文件引用类:

@Entity
@Table(name = "TB_FILE_REFERENCE")
public class FileReference extends BaseNamedEntity<String> {

    private String type;

    public FileReference() {}

    @Id    
    @TableGenerator(name="genFileReference", table="TB_ID_GENERATOR",
            pkColumnName="ID_NAME", valueColumnName="ID_VAL",
            pkColumnValue="TB_FILE_REFERENCE", allocationSize=1)
    @GeneratedValue(strategy=GenerationType.TABLE, generator="genFileReference")
    @Column(name = "ID_FILE_REFERENCE", unique = true, nullable = false)
    public String getId() {
        return super.getId();
    }
    @Override
    public void setId(String id) {
        super.setId(id);
    }

    @Column(name = "TYPE")
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }       
}

服务类:

@Path("/banner")
public class BannerImageService extends BaseServiceFacade<BannerImage, Integer> {
        @SuppressWarnings("unchecked")
    @Override
    public Crud<BannerImage, Integer> lookupService() throws ServiceLocatorException {          
        return ServiceLocator.getInstance()
                .getLocalHome(ServicesConstants.BANNER_IMAGE_SERVICE);      
    }

    @Override
    protected String getDefaultGetQuery() {
        return BannerImageDAO.GET_BY_ID_FETCH_FILE_REF;
    }

    @Override
    protected String getDefaultQuery() {
        return BannerImageDAO.GET_ALL_FETCH_FILE_REF;
    }    
}

获取BaseServiceFacade的REST方法:

@Override
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Path("/{id}")
public T get(@PathParam("id") ID id) {
    try {
        if (!validateID(id)) {
            logMessage("Invalid Entity ID: " + id);
            return null;    
        }           

        String defaultGetQuery = getDefaultGetQuery();
        if (defaultGetQuery != null) {
            Map<String, Object> mapParams = new HashMap<String, Object>();
            mapParams.put("id", id);
            List<T> entityList = getService().search(defaultGetQuery, mapParams);
            if (entityList != null && entityList.size() == 1) {
                T ent = entityList.get(0);
                return ent;
            } else {
                logMessage("Invalid search by Entity ID: " + id);
            }

        } else {                
            return getService().findById(clazz, id);    
        }           

} catch (ServiceException e) {
    serviceException(e);
} catch (Exception ex) {
    logException(ex);
}
    return null;
}

最后是从 entityManager 读取的 Service Bean EJB:

public class BaseServiceBean<T extends IEntity<ID>, ID extends Serializable> implements Crud<T,ID> {

        // ... generic methods to be reused by subclasses

        @Override
        public List<T> search(String queryOrNamedQuery) throws ServiceException {
            return search(queryOrNamedQuery, null, 0, 0);
        }

        @SuppressWarnings("unchecked")
        public List<T> search(String namedQueryOrHql, Map<String, Object> parameters, int start, int chunkSize) {
            try {
                Query query = createQuery(namedQueryOrHql, getQueryType(namedQueryOrHql));
                if (start > 0) {
                    query.setFirstResult(start);
                }
                if (chunkSize > 0) {
                    query.setMaxResults(chunkSize);
                }
                addParameters(query, parameters);
                List<T> result = query.getResultList();
                afterSearch(result); 
                return result;

            } catch (NoResultException nre) {
                nre.printStackTrace();
            } catch (ClassCastException cce) {
                cce.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();            
            }
            return null;
        }

    protected void afterSearch(List<T> result) {

    }
// etc...

BannerImageService 的具体实现类:

    @Stateless(mappedName="ejb/BannerImageService")
    public class BannerImageServiceBean extends BaseServiceBean<BannerImage, Integer> implements BannerImageServiceBeanRemote, BannerImageServiceBeanLocal {

    @Override
    protected void afterSearch(List<BannerImage> result) {

        if (result != null && result.size() == 1) {         
            BannerImage bannerImage = result.get(0);
            bannerImage.getFileReference();
        }

        super.afterSearch(result);
    }

// additional code ...

当我尝试获取 BannerImage 类及其对应的 FileReference 成员时,我总是得到 NULL,即使在我的数据库中存在现有的外键:

JPQL:

"SELECT a FROM BannerImage a join fetch a.fileReference WHERE a.id = :id";

生成的 SQL:

SELECT t1.ID_BANNER_IMAGE, t1.LABEL_TEXT, t1.LABEL_TITLE, t1.TYPE, 
t1.ID_FILE_REFERENCE, t0.ID_FILE_REFERENCE, t0.NAME, 
t0.TYPE FROM TB_FILE_REFERENCE t0, TB_BANNER_IMAGE 
t1 WHERE (t0.ID_FILE_REFERENCE = t1.ID_FILE_REFERENCE) AND t1.ID_BANNER_IMAGE = 1

在我的数据库中,记录显示了正确的参考:

BANNER_IMAGE:

1;"";"main";"2bdbb063d0d0ee2939c89763945d9d9e";"banner1.png";"image/png"

如果我执行:

select * from TB_FILE_REFERENCE where ID_FILE_REFERENCE = '2bdbb063d0d0ee2939c89763945d9d9e'

我可以在数据库中找到记录,虽然我的 EclipseLink JPA 实现总是返回 null:

EclipseLink 版本 2.5.2-M1

这就是实体如何从服务层传递到

有人可以帮忙指出为什么 JOIN FETCH 不能正常工作吗?

【问题讨论】:

  • 检查如果你使用访问器方法而不是在调试器中检查字段会发生什么。编织惰性关系意味着该字段在被访问之前不会被填充。您可以通过检查访问惰性关系时发出的 SQL 来检查 fetch 连接是否有效 - 如果发出 SQL 来查询它,则说明有问题。
  • 每当我尝试执行 getFileReference() 时,我都会得到:[EclipseLink-7242](Eclipse Persistence Services - 2.5.0.v20130507-3faac2b):org.eclipse.persistence.exceptions.ValidationException 异常说明: 尝试使用具有空会话的间接遍历关系。这通常发生在具有未实例化 LAZY 关系的实体被序列化并且在序列化之后遍历该惰性关系时。为避免此问题,请在序列化之前实例化 LAZY 关系
  • 这意味着实体已被序列化,因此工厂不再可用于读取关系。您使用的是什么版本的 Eclipselink,您能否显示您用于在实体中读取的代码?您之前是否阅读过实体,或者这是一个明确的实体管理器上下文?
  • 更新了添加上述信息的问题。我从 EJB 读取实体并返回 List result = query.getResultList(); 的结果
  • afterSearch 是做什么的?如果您只是执行一个简单的 JPQL “SELECT a FROM BannerImage a join fetch a.fileReference WHERE a.id = :id”并立即检查 fileReference,它是否被提取?我能看到这种情况发生的唯一方法是,如果刷新返回的 BannerImage,这将重置间接/惰性关系

标签: jpa null eclipselink lazy-loading fetch


【解决方案1】:

我遇到了类似的问题,仔细观察后发现此问题仅发生在最近创建/保存的实体上。然后我认为它与eclipselink缓存有关。我通过在进行 join fetch JPQL 查询之前添加这一行来解决这个问题,

em.getEntityManagerFactory().getCache().evictAll();
em.createQuery("SELECT a FROM BannerImage a join fetch a.fileReference WHERE a.id = :id").getResultList();

HTH!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-30
    • 1970-01-01
    • 2015-02-07
    • 1970-01-01
    • 2016-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多