2013-02-25 84 views
4

我有一个表的字符串值为它所指向的实体的条形码。不幸的是,它不是一个外键,它只是一个字符串,所以不存在映射。这使得联合操作变得困难。我想知道如何将这个对象加入另一个没有定义关系的表中。例如:CriteriaQuery加入字符串值

@Entity 
@Table(name = "TblSample", schema = SCHEMA, catalog = CATALOG) 
public class Sample { 

    @Id 
    @Column(name = "id", nullable = false) 
    private int id; 

    @Column(name = "barcodeEntity", nullable = false) 
    private String barcodeEntity; 

    @OneToOne 
    @JoinColumn(name = "barcodeContainer", nullable = false) 
    private Container container; 

    ... 
} 

@Entity 
@Table(name = "TblSoil", schema = SCHEMA, catalog = CATALOG) 
public class Soil { 

    @Column(name = "barcode", nullable = false) 
    private String barcode; 

    @Column(name = "name", nullable = false) 
    private String name; 
    ... 

} 

@Entity 
@Table(name = "TblLeaf", schema = SCHEMA, catalog = CATALOG) 
public class Leaf { 

    @Column(name = "barcode", nullable = false) 
    private String barcode; 

    @Column(name = "name", nullable = false) 
    private String name; 
    ... 
} 

@Entity 
@Table(name = "TblContainer", schema = SCHEMA, catalog = CATALOG) 
public class Container { 

    @Column(name = "barcode", nullable = false) 
    private String barcode; 

    @Column(name = "name", nullable = false) 
    private String name; 

    @Column(name = "location", nullable = false) 
    private String location; 
    ... 
} 

所以,我想用一个CriteriaQuery中可以返回所有的样品和加入的,它是取自实体。我已经开始编写它,但是当我试图找出如何去做时,我陷入了困境。在SQL它想是这样的:

SELECT TOP 100 
    sample.Id 
, sample.barcodeEntity 
, leaf.name 
, soil.name 
, sample.barcodeContainer 
, container.name 
, container.location 
FROM TblSample sample 

    LEFT JOIN TblSoil leaf on 
    soil.barcode = sample.barcodeEntity 

    LEFT JOIN TblLeaf leaf on 
    leaf.barcode = sample.barcodeEntity 

    JOIN TblContainer container on 
    container.barcode = sample.barcodeContainer 

我想,相关的JPA CriteriaQuery中会是这个样子:

public void findSamples(Map<String, String> filterCriteria) { 
    final CriteriaBuilder builder = getEntityManager().getCriteriaBuilder(); 
    final CriteriaQuery<SampleLocation> query = builder.createQuery(SampleLocation.class); 
    final Root<Sample> derivation = query.from(Sample.class); 
    // Note that the next two lines don't work 
    final Join<Leaf> joinOnLeaf = derivation.join(Sample_.barcodeEntity, JoinType.LEFT); 
    final Join<Soil> joinOnSoil = derivation.join(Sample_.barcodeEntity, JoinType.LEFT); 
    final Join<Container> joinOnContainer = derivation.join(Sample_.barcodeContainer); 

    CompoundSelection<SampleLocation> cSelect = 
     builder.construct(SampleLocation.class, sample.Id, sample.entitybarcode, joinOnLeaf.get(Leaf_.name), joinOnLeaf.get(Soil_.name), sample.barcodeContainer, joinOnContainer.get(Container_.name), joinOnContainer.get(Container_.location)); 
    query.select(cSelect); 

    TypedQuery<SampleLocation> typedQuery = entityManager.createQuery(query); 
    typedQuery.setMaxResults(100); 

    return typedQuery.getResults(); 
} 

任何想法如何,我可以执行左连接操作?我无法根据CriteriaQuery API做出决定。看起来像是应该存在的东西。

+0

老实说,一旦查询得到这个复杂度,我会诉诸于HQL(假设你使用的是Hibernate ...) – 2013-02-25 13:56:59

+0

作为最后的手段,我可​​能会试试这个。不过,我宁愿不要因为它不安全。我们大多数是Java开发人员,所以我们从这个角度来看更适合执行数据库工作。说了这也许是这些特殊情况之一。如果我无法使用JPA,那么我认为我们将开发一个独立的项目来执行复杂的查询(比如这个),以便将其与代码库的其余部分隔离开来。一旦将SQL引入代码库中,维护起来可能会变得非常困难(正如我发现的那样)。 – Craig 2013-02-26 07:06:14

回答

1

我建议两个查询。对于第一个,获取与您的条形码字符串相关的主键值。然后使用第二个查询中的数据。

+0

我一直希望一气呵成,但你可能是对的。也许我可以说服DBA将表更改为使用外键而不是条形码字符串。这会让生活变得更容易。 – Craig 2013-02-26 06:54:51