我有一张 table 产品(ProductId、Name)和 产品价格(产品 ID、市场、价格)
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");
}
};
}
但是,这只会导致(我尝试写“市场”,“市场”,...)
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 过滤器
这次我写在产品实体
@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 提供可行的解决方案?谢谢!
最佳答案
第二种方法实际上是正确的。尝试更改您的实体和 creteria 查询。
产品表:
@Entity
@Table(...)
public class Product {
@Id
private int ProductId;
private String name;
@OneToMany(mappedBy = "products")
private List<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;
关于java - @OneToMany 实际上是带有参数的 OneToOne/@Formula,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31962439/