2013-02-25 34 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