2012-08-03 12 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

相关问题