У меня есть четыре стола, к которым мне нужно присоединиться. Эти четыре таблицы:
Продукт имеет услугу, а услуга имеет тип и продолжительность.
Пользователь выбирает продукт, тип, услугу и продолжительность обслуживания.
В случае, если сервис недоступен для выбранного типа и продолжительности, я хотел бы иметь возможность получить сервис, который имеет тип с более низким приоритетом (приоритет — атрибут в таблице service_type).
В php (Laravel) я могу присоединиться так:
DB::table('product')
->join('product_service', 'product_service.product_id', '=', 'product.id')
->join('service', 'service.id', '=', 'product_service.service_id')
->join('service_type', 'service.type_id', '=', 'service_type.id')
->join('service_duration', 'service.duration_id', '=', 'service_duration.id')
->where('product.id', id)
->where('service_type.priority', '<', priority)
->where('service_duration.duration', duration)
->where('maintenance.active', 1)
->orderBy('service_type.priority', 'desc')
->select('service.*')
->first();
Как это можно сделать с помощью Hibernate Entity Criteria? Я хочу начать с присоединения со стороны продукта, но в конце выберите сервис.
Мои отношения определены так:
Класс продукта
@Entity
@Table(name = "product")
public class product implements Serializable {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "id.product", cascade=CascadeType.ALL)
private Set<ProductService> services = new HashSet<ProductService>();
}
Класс ProductService:
@Entity
@Table(name = "product_service")
@AssociationOverrides({ @AssociationOverride(name = "id.service", joinColumns = @JoinColumn(name = "service_id")),
@AssociationOverride(name = "id.product", joinColumns = @JoinColumn(name = "product_id"))})
public class ProductService implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private ProductServicePK id = new ProductServicePK();@Column(name = "price")
private Float price;
@Column(name = "code")
private String code;
}
ProductServicePK Класс:
@Embeddable
public class ProductServicePK implements Serializable {
private static final long serialVersionUID = 1L;
@ManyToOne
private Product product;
@ManyToOne
private Service service;
}
Класс обслуживания:
@Entity
@Table(name = "service")
public class Service implements Serializable {
@Id
@Column(name = "id")
private Long id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "type_id")
private ServiceType type;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "duration_id")
private ServiceDuration duration;
}
Таким образом, объект, который «содержит» ссылку на другой объект, является объектом продукта. Поэтому я не уверен, как получить услугу для этого продукта, который имеет приоритет ниже выбранного.
Я хочу сделать это с критериями или HQL.
Ваши Hibernate Отдельные критерии будут нравиться:
DetachedCriteria criteria = DetachedCriteria.forClass(Product.class, "product")
.criteria.createAlias("product.product_service", "productService")
.createAlias("productService.service","service")
.createAlias("service.service_type","serviceType")
.createAlias("service_duration","serviceDuration")
.add(Restrictions.eq("product.id", id))
.add(Restrictions.gt("serviceType.priority", priority))
.add(Restrictions.eq("serviceDuration.duration", duration))
.setProjection(add your productService projection here)
getExecutableCriteria(session).SetMaxResults(1) ;
Но я не понимаю вашу точку зрения, почему вы используете from query
на product
вместо product_service
?, потому что вам нужно product_service
подробности.
Вы можете использовать querycriteria.html, вот документ этого->https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querycriteria.html
или вы можете использовать hql ->https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html для достижения вашего результата.
По-видимому, JPA Criteria API не поддерживает то, что мне нужно при использовании составного шаблона PK. Я нашел это где-то упоминалось Вот. Поэтому я обнаружил, что лучшим решением было использование HQL:
Query q = session.createQuery("select s "+ "from Service s "+ "join s.productService as ps "+ "join s.type as t "+ "where s.duration = :durationId "+ "and ps.id.product.id = :productId "+ "and t.priority <= :priorityValue "+ "order by t.priority desc");
q.setLong("durationId", durationId);
q.setInteger("priorityValue", priorityValue);
q.setLong("productId", productId);
return (Service) q.setMaxResults(1).uniqueResult();