将对象作为查询参数传递并排除ID列

时间:2012-08-03 16:05:07

标签: java jpa

我有以下内容:

@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

如您所见,Car类有一个“安全”对象,它是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 个答案:

答案 0 :(得分: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