2012-08-03 46 views
1

我有以下幾點:傳遞一個對象作爲查詢參數,並排除ID列

@Entity 
@NamedQuery(name = "listCarsBySecurity", query = "SELECT c FROM Car c WHERE c.security = :security" 
public class Car { 
    @Id 
    @GeneratedValue 
    private Long id; 

    @NotNull() 
    @Column(nullable = false) 
    private String make; 

    @NotNull() 
@Column(nullable = false) 
private String model; 

    // Some more fields 

    @NotNull() 
@OneToOne (fetch = FetchType.LAZY, orphanRemoval=true) 
private Security security = new Security(); 

    // Some getters and setters 

正如你可以看到,汽車類有一個「安全」的對象是LAZY牽強。安全類的樣子:

@Entity 公共類安全{

@Id @GeneratedValue 
private Long id; 

// Security equipment. Add in alphanumerical order 
private boolean abs; 
private boolean airbag; 
private boolean antispin; 

// Some getters and setters 

,你可以看到,命名查詢列表嘗試列出具有安全實體等於提供的安全對象的所有汽車。

持久的方法是這樣的:

@Stateless 
public class CarEJB { 

    @PersistenceContext(unitName = "carcmsPU") 
    private EntityManager em; 

    public List<Car> listCarsBySecurity(Security security) { 
     TypedQuery<Car> query = em.createNamedQuery("listCarsBySecurity", Car.class); 
     query.setParameter("security", security); 
     return query.getResultList(); 
    } 

和JUnit測試看起來像:

@Test 
public void searchCar() throws Exception { 
    // Looks up the EJBs   
    carEJB = (CarEJB) ctx.lookup("java:global/classes/CarEJB"); 

    // Create a new Ferrari with security = ABS brakes and Airbag 
    Car car = new Car(); 
    car.setMake("Ferrari"); 
    car.setModel("Some model"); 
    car.setSubModel("Some sub model"); 
    car.setEngine("Some engine"); 
    car.setYear(1999);   
    car.getFuel().setGasoline(true); 
    car.setGearbox(Gearbox.AUTOMATIC); 
    car.setKilometres(323); 
    car.setDescription("This is a description"); 
    Security security = new Security(); 
    security.setAbs(true); 
    security.setAirbag(true); 
    car.setSecurity(security); 

    carEJB.createCar(car); // Persist 

    // Create a new security object and match it to the former one 
    Security securityObject = new Security(); 
    securityObject.setAbs(true); 
    securityObject.setAirbag(true); 


    List<Car> carList = carEJB.listCarsBySecurity(securityObject); 

    assertTrue("Should contain at least 1 car with ABS and Airbag", carList.size() > 0); 
    for (Car carTemporary : carList) { 
     System.out.println(carTemporary.toString()); 

    } 



} 

的事情是,在列表中不包含任何車都沒有。我想我知道爲什麼;指定的查詢會嘗試將security_id與NULL匹配(因爲我沒有定義它)。

我的問題是:如何通過傳遞一個對象作爲查詢參數沒有ID和通過不指定所有應在該對象內進行比較的字段來執行查詢? (或如何從搜索中排除該ID)?

問候

回答

1

可以使用OR和傳遞對象的屬性中的每一個定義了一個名爲查詢。您還可以使用Criteria API根據要查詢的字段構建查詢。既然你已經有了一個命名的查詢,我會把那一個留給你。

如果你決定這樣做(如果你的實體有太多的屬性,那麼按照字段比較來說,強硬的字段是瘋狂的)。使用標準,你可以做這樣的事情:

CriteriaBuilder builder = entityManager.getCriteriaBuilder(); 
CriteriaQuery<Car> query = builder.createQuery(Car.class); 
Root<Car> queryRoot = query.from(Car.class); 
query.select(queryRoot); 

Path<String> pathToYourField = root.get(yourField); //yourField is a variable containing the field. 
                //You can store all the variables in a list, iterate 
                //over them and do this for each one. 
query.where(builder.and(builder.equal(pathToYourField, "particularValue"))); //You compare the path against a value. 
//Rest of the fields/paths 

TypedQuery<Car> typedQuery = entityManager.createQuery(query); 
List<Car> cars = typedQuery.getResultList(); 

編輯:關於性能,檢查此鏈接:

  1. JPA Criteria vs NamedQueries
  2. Another answer regarding Criteria vs HQL
  3. Criteria overhead discussion
+0

您好,感謝爲您的答案!我認爲你的解決方案對我的應用程序來說很好,除了性能。前端是一個AJAX網頁,並會執行很多查詢。使用此解決方案是否會有很大的性能損失,例如安全類中的20個字段? – kungcc 2012-08-03 17:26:56

+0

Criteria API最適合動態查詢。如果您發現自己經常使用生成的查詢,則可以考慮將其改爲NamedQuery。就性能而言,標準可能會慢幾毫秒,但最終,據我所知,沒有任何意義上的差異。我已經添加了一些鏈接到我的答案與一些有趣的文章。 – Gamb 2012-08-03 19:04:58