Java EAV模型弹簧数据jpa的复杂选择
我有一个如下的产品实体,它是简单的版本Java EAV模型弹簧数据jpa的复杂选择,java,sql,jpa,spring-data-jpa,entity-attribute-value,Java,Sql,Jpa,Spring Data Jpa,Entity Attribute Value,我有一个如下的产品实体,它是简单的版本 @Entity @Table(name = "product") public class Product { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @OneToMany(mappedBy = "product") private List<ProductAtt> attributes; } 因此,我创建了一个具
@Entity
@Table(name = "product")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@OneToMany(mappedBy = "product")
private List<ProductAtt> attributes;
}
因此,我创建了一个具有额外值属性的关系实体,如下所示
@Entity
@Table(name = "product_att")
public class ProductAtt implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@ManyToOne
@JoinColumn
private Product product;
@ManyToOne
@JoinColumn
private Attribute attribute;
private int value;
}
现在我想找到所有具有自定义值的属性的产品。例如,属性1的值为3,属性2的值为40和
最简单和最有效的查询是什么 由于要查询的属性数量在设计时未知,因此必须使用Spring Data JPA支持的动态查询机制之一。查询当然可以使用JPA规范或标准API构建 如果使用QueryDSL支持,则可以使用exists的子查询。下面的示例显示了如何在假设Java8和QueryDSL4的情况下实现这一点
interface ProductRepository
extends CrudRepository<Product, Long>
, QueryDslPredicateExecutor<Product> {
default Iterable<Product> findAllByAttributes(final Map<String, String> attributes) {
final QProduct root = QProduct.product;
BooleanExpression query = root.isNotNull();
for (final String attribute : attributes.keySet()) {
final QProductAttribute branch = root.attributes.any();
final BooleanExpression subquery = branch.attribute.name.equalsIgnoreCase(attribute)
.and(branch.value.equalsIgnoreCase(attributes.get(attribute)));
query = query.and(JPAExpressions.selectFrom(QProductAttribute.productAttribute).where(subquery).exists());
}
return findAll(query);
}
}
应该注意的是,数据库设计必然会出现性能问题,因为同一个表ProductAttr包含的次数与要搜索的属性包含的次数相同。这不是QueryDSL、JPA、Hibernate、SQL或数据库服务器的问题,而是数据模型本身,也称为EAV模型。取决于要检查的属性数量。这是一个属性列表,从一个属性到多个属性。我认为最好的方法是使用标准。如果要检查每个属性,而不是例如属性1、3和5。。。然后,您只需迭代列表并请求值,然后向条件添加一个谓词,最后就可以执行查询了。这可能不是最好的解决方案,但却是我能想到的最简单的解决方案,因为您有很多变量属性来检查TNX以获得全面的答案。但这是一个非常慢的查询,我想我应该避免使用这个数据模型,而是使用空列,以提高速度
interface ProductRepository
extends CrudRepository<Product, Long>
, QueryDslPredicateExecutor<Product> {
default Iterable<Product> findAllByAttributes(final Map<String, String> attributes) {
final QProduct root = QProduct.product;
BooleanExpression query = root.isNotNull();
for (final String attribute : attributes.keySet()) {
final QProductAttribute branch = root.attributes.any();
final BooleanExpression subquery = branch.attribute.name.equalsIgnoreCase(attribute)
.and(branch.value.equalsIgnoreCase(attributes.get(attribute)));
query = query.and(JPAExpressions.selectFrom(QProductAttribute.productAttribute).where(subquery).exists());
}
return findAll(query);
}
}