@OneToMany实际上是带参数的OneToOne / @Formula

时间:2015-08-12 10:21:49

标签: java spring hibernate jpa spring-boot

我有一张桌子 产品(ProductId,Name)和 ProductPrices(ProductId,Market,Price)

ProductPrices有一个compositeKey(ProductId,Market)。对于给定的市场,产品在该市场中的价格为0..1。

第一种方法@Formula

市场在运行时是已知的,并且可以根据请求进行更改。 在第一次尝试对ProductEntity建模时,我采用了@Formula注释,如下所示:

@Entity
@Table(...)
public class Product {
@Id
private int ProductId;

private String name;

@Formula("(SELECT TOP 1 Price FROM ProductPrices p WHERE p.ProductId = ProductId  AND p.Market='Berlin')")
private double price;
}

但显然,市场是经过精心编制的,因为注释需要是静态的最终字符串。 [所以没有@Formula(" ......" + getCurMarket())]。

第二种方法,@ OneToMany

为价格选择一个单独的实体类,并在产品实体中引用它们:

@OneToMany(mappedBy = "product")
private List<Price> price;

getPrice()中,如果列表为空,我总是可以返回第一个条目(永远不会有更多......)或者没有。

然后我想在ProductService中创建一个要使用的谓词/规范。例如:

public static Specification<Product> marketEquals(final String market) {
    return new Specification<Product>() {
        @Override
        public Predicate toPredicate(Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

            CriteriaQuery<String> q = cb.createQuery(String.class);
            Root<Price> price = q.from(Price.class);
            return price.get("Market").in("Berlin");
        }
    };
}

然而,这只会导致(我尝试写作&#34;市场&#34;,&#34;市场&#34;,......)

org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'generatedAlias1.market' [select generatedAlias0 from ...backend.entities.Product as generatedAlias0 where generatedAlias1.market in (:param0)]

第三种方法,Hibernate / JPA Filter

这一次,我在产品实体中写道

 @OneToMany(mappedBy = "product")
    @Filters( {
        @Filter(name="marketFilter", condition="Market = :market")
    } )
  private List<Price> price;

同样,我想在ProductService中填充此过滤器,但我无法抓住CurrentSession。我尝试了Spring-way,添加@Autowired private SessionFactory sessionFactory;并通过

进行配置
Filter filter =  sessionFactory.getCurrentSession().enableFilter("marketFilter");
filter.setParameter("market", "Berlin" );

但我无法抓住正确的背景,如org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.hibernate.SessionFactory

谁可以建议如何将数据库模式建模为实体,或者可以将工作解决方案指向方法2和3?谢谢!

1 个答案:

答案 0 :(得分:1)

第二种方法实际上是正确的。尝试改变你的实体和creteria查询。

产品表:

@Entity
@Table(...)
public class Product {
@Id
private int ProductId;

private String name;

@OneToMany(mappedBy = "products")
private List<ProductPrices> ProductPrices;
}

ProductPrices表:

@Entity
@Table(...)
public class ProductPrices {
@Id
private int ProductPriceId;

private String market;

private double price;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_id") //foreign key reference
private Product products
}

产品服务:

    CriteriaBuilder cb = em.getCriteriaBuilder();
                CriteriaQuery<Product> qry = cb.createQuery(Product.class);
                Root<Product> root = qry.from(Product.class);
                Join<Product, ProductPrices> price = root.join("ProductPrices");
                List<Predicate> conditions = new ArrayList<>();
                conditions.add(cb.equal(price.get("products"), "Berlin"));

                TypedQuery<Product> typedQuery = em.createQuery(qry
                        .select(root)
                        .where(conditions.toArray(new Predicate[] {}))
                        .orderBy(cb.asc(root.get("Berlin")))
                        .distinct(true)
                );

return typedQuery;