Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java EAV模型弹簧数据jpa的复杂选择_Java_Sql_Jpa_Spring Data Jpa_Entity Attribute Value - Fatal编程技术网

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);
  }
}