2011-09-27 52 views
0

我有一个实体:JPA可空JoinColumn

public class Foo { 
    @Id 
    @GeneratedValue 
    private Long id; 

    private String username; 

    @ManyToOne(cascade = { CascadeType.MERGE }, fetch = FetchType.LAZY, optional = true) 
    @JoinColumn(name = "ParentID", nullable = true) 
    private Foo parent; 

    // other fields 
} 

利用这种关系,每个Foo对象具有父,除了在DB中的第一富实例具有NULL PARENTID。当我尝试创建通过标准API查询,并尝试搜索使用任何它的第一个Foo对象(null父ID)的属性(ID,用户名等),我得到一个:

javax.persistence.NoResultException: No entity found for query 

如何应该在这种情况下实施JoinColumn?我应该如何获得具有空父ID的数据库中的第一个Foo对象?

感谢

更新2011年9月28日

什么,我想实现的是看lookfor所有FOOS使用用户名在“foo”的开始,并希望作为单独的对象使用返回然后:

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder; 
CriteriaQuery<FooDto> criteriaQuery = criteriaBuilder.createQuery(FooDto.class); 
Root<Foo> foo = criteriaQuery.from(Foo.class); 

criteriaQuery.multiselect(foo.get("id"), foo.get("username"), foo.get("parent").get("username"), foo.get("property1") 
//other selected properties); 

Predicate predicate = criteriaBuilder.conjunction(); 
predicate = criteriaBuilder.and(predicate, criteriaBuilder.like(foo.get("username").as(String.class), criteriaBuilder.parameter(String.class, "username"))); 
// other criteria 

criteriaQuery.where(predicate); 

TypedQuery<FooDto> typedQuery = entityManager.createQuery(criteriaQuery); 
typedQuery.setParameter("username", "foo%"); 
// other parameters 

// return result 

假设用户名是foo1和Foo2和foo3其中foo1具有null父,结果集将只返回foo2的和foo3即使foo1具有与指定的谓词启动一个用户名。 并寻找foo1单独将抛出一个

javax.persistence.NoResultException: No entity found for query 

有没有办法仍然包括与其余结果的foo1?或foo1将永远是一个特例,因为我必须添加一个标准,指定父项为空?或者,也许ai错过了joinColumn中的一个选项来执行此操作。

感谢

修订周四9月29日13时03分41秒PHT 2011 @mikku 我已经更新上面(property1)后的标准的一部分,因为我认为这是负责的部分因为foo1不包含在结果集中。

下面是生成的查询的从日志中的部分观点:

select 
    foo.id as id, 
    foo.username as username, 
    foo.password as password, 
    foo.ParentID as parentId, 
    foo_.username as parentUsername, 
    foo.SiteID as siteId, 
from FOO_table foo, FOO_table foo_ cross join Sites site2_ 
where foo.ParentID=foo_.id and foo.SiteID=site2_.id and 1=1 
and foo.username=? and site2_.remoteKey=? limit ? 

,这不会返回Foo1,显然是因为用户名值是foo_这就是为什么我原来的问题是“我应该怎么去Foo1 ”。

在部分我已经评论说,生病使用SelectCase,并与你的第一个回复混合起来,我所做的是对多选添加此部分:

criteriaBuilder 
    .selectCase() 
     .when(criteriaBuilder.isNotNull(agent.get("parent")), agent.get("parent").get("username")) 
     .otherwise(criteriaBuilder.literal("")), 

更换

foo.get("parent").get("username") 

但是,这也不会得到Foo1。我最后的手段虽然效率低下,但可能会检查参数是否为Foo1,并创建一个criteriaQuery指定用户名的文字值,否则使用默认查询。

建议/替代方案非常感谢。

回答

1

编辑:

在你编辑的问题可空joincolumn不是问题 - FooDto失踪建设,多选等都是。您可以通过以下实现自己的目标:

查询:

/** 
    * Example data: 
    * FOO 
    * |id|username|property1|parentid| 
    * | 1| foo | someval| null|<= in result 
    * | 2| fooBoo | someval2|  1|<= in result 
    * | 3|somename| someval3| null| 
    */ 
    CriteriaBuilder cb = em.getCriteriaBuilder(); 
    CriteriaQuery<FooDto> c = cb.createQuery(FooDto.class); 
    Root<Foo> fooRoot = c.from(Foo.class); 
    Predicate predicate = cb.like(fooRoot.get("username").as(String.class), 
            cb.parameter(String.class, "usernameParam")); 

    c.select(
      cb.construct(FooDto.class, 
         fooRoot.get("id"), 
         fooRoot.get("username"), 
         fooRoot.get("property1"))) 
    .where(predicate); 

    TypedQuery<FooDto> fooQuery = em.createQuery(c); 
    fooQuery.setParameter("usernameParam", "foo%"); 

    List<FooDto> results = fooQuery.getResultList(); 

对象保存数据:

public class FooDto { 
    private final long id; 
    private final String userName; 
    private final String property1; 
    //you need constructor that matches to type and order of arguments in cb.construct 
    public FooDto(long id, String userName, String property1) { 
     this.id = id; 
     this.userName = userName; 
     this.property1 = property1; 
    } 

    public long getId() { return id; } 
    public String getUserName() { return userName; } 
    public String getProperty1() { return property1; } 

} 
+0

感谢您的回答。遗憾的是,我忘了在帖子上放置实体注释。顺便说一下,基于你的推荐答案,我假设我需要为第一个foo的情况有一个单独的查询,因为它有一个空的父亲?我已经用我希望实现的内容更新了我发布的问题。 谢谢 – geneqew

+0

你不需要特殊情况。这是你的原始问题的答案:“我应该如何获得具有空父ID的数据库中的第一个Foo对象?” –

+0

感谢您的回复。 &道歉我已经忘记包括FooDto构造函数,我已经有+(multiselect上面说的是工作给定的构造函数存在相同的参数类型和顺序,因为c的类型已经被指定为FooDto)。但是,因为我的后续问题是: 有没有办法将foo1与其他结果一起包含?或foo1将永远是一个特例,因为我必须添加一个标准,指定父项为空? 我结束了混合你的第一个答案,指定一个选择案例链接的空标准。 再次感谢 – geneqew