Выполнение NOT IN QUERY для объектов со связями «многие ко многим» в JPA - PullRequest
0 голосов
/ 03 ноября 2018

У меня есть два объекта JPA, а именно Product и Order, которые имеют отношения многие ко многим друг с другом.

@Entity
@Table(name = "orders")
@JsonInclude(NON_NULL)
public class Order implements Serializable {

    public static final int PRECISION = 2;

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @JsonIgnore
    private String orderId;

    @Column(unique = true, nullable = false, length = 8)
    private String orderNumber;

    @Column
    private BigDecimal discount;

    @Column(nullable = false)
    private BigDecimal taxPercent;

    private BigDecimal total;

    private BigDecimal totalTax;

    private BigDecimal grandTotal;

    @Column(length = 10)
    private String status;

    @ManyToMany(cascade = ALL, fetch = FetchType.EAGER)
    @JoinTable(
            name = "order_product",
            joinColumns = @JoinColumn(name = "order_id", updatable = false, nullable = false),
            inverseJoinColumns = @JoinColumn(name = "product_id", updatable = false, nullable = false)
    )
    private List<Product> products = new ArrayList<>();

    public BigDecimal getTotal() {
        BigDecimal total = new BigDecimal(ZERO);
        if (products == null || products.isEmpty()) {
          return total;
        }
        for (Product product : products) {
            total = total.add(product.getPrice());
        }
        return scaled(total);
    }

    public BigDecimal getTotalTax() {
        return scaled(getTotal().multiply(taxPercent.divide(new BigDecimal("100"))));
    }

    public BigDecimal getGrandTotal() {
        BigDecimal total = this.getTotal().add(getTotalTax());
        if (discount != null) {
            return scaled(total.subtract(discount));
        }
        return scaled(total);
    }

    private BigDecimal scaled(BigDecimal value) {
        return value.setScale(PRECISION, ROUND_FLOOR);
    }

    .. Getters and setters ... 

}

и Продукт

@Entity
@Table(name = "products")
public class Product implements Serializable {

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @JsonIgnore
    private String productId;

    @Column(unique = true, nullable = false, length = 10)
    private String upc;

    @Column(unique = true, nullable = false, length = 13)
    private String sku;

    @Column(nullable = false)
    private String description;

    @Column(nullable = false)
    private BigDecimal price;

    public BigDecimal getPrice() {
      return price;
    }

    @ManyToMany(mappedBy="products", fetch=FetchType.EAGER)
    @JsonIgnore
    private List<Order> orders = new ArrayList<>();

    // Getters and setters.
}

Это мой DML

insert into products (product_id, upc, sku, description, price) values ('1', '1257833283', '9394550220002', 'Diva Jeans', 39.99);
insert into products (product_id, upc, sku, description, price) values ('2', '1358743283', '7394650110003', 'Polo Shirt', 19.99);
insert into products (product_id, upc, sku, description, price) values ('3', '1458843283', '7394750120000', 'Floral Swing Skirt', 69.99);
insert into products (product_id, upc, sku, description, price) values ('4', '1358753283', '7394850130001', 'Denim Short', 29.99);
insert into products (product_id, upc, sku, description, price) values ('5', '1258793283', '7394950140000', 'True Skinny Jeans', 49.99);

insert into orders (order_id, order_number, tax_percent, status) values ('1', 'RTL_1001', 10, 'SHIPPED');
insert into orders (order_id, order_number, discount, tax_percent, status) values ('2', 'RTL_1002', 15.55, 10, 'FULFILLED');


insert into order_product (order_id, product_id) values ('1', '1');
insert into order_product (order_id, product_id) values ('1', '2');
insert into order_product (order_id, product_id) values ('2', '2');

Я хочу выбрать только те товары, которые

  1. Если я запрашиваю товары по несуществующему заказу (скажем, с order_id = 3, который не существует), я хочу вернуть все подходящие товары, поскольку заказ еще не был создан.

  2. Если я запрашиваю товары по существующему заказу, я хочу, чтобы база данных возвращала все товары, не связанные с заказом. Например, для order_id = 1 я хочу вернуть продукты с id = 3, 4 и 5. Поскольку order_id = 1 уже связан с product_id = 1 и 2, я не хочу, чтобы эти продукты возвращались.

Если бы я написал SQL-запрос JDBC

SELECT p.product_id
FROM Product p
WHERE NOT EXISTS 
    (
        SELECT 1 
        FROM order_product 
        WHERE product_id = p.product_id
            AND
            order_id = ?
    )
    OR 
    NOT EXISTS
    (
        SELECT 1 
        FROM order_product 
        WHERE order_id = ?
    )

Я не знаю, как использовать JPA для создания аналогичного запроса. Все, что я могу думать, это что-то вроде этого.

  1. Создать репозиторий Product, который наследуется от JPARepository

  2. Получить все продукты из Таблицы продуктов, включая продукты из таблицы order_product.

  3. Получить продукты для данного идентификатора заказа с помощью JPA и удалить указанные продукты из продуктов в (2)

Я надеюсь, что есть лучший способ сделать это.

1 Ответ

0 голосов
/ 03 ноября 2018
Order order = em.getReference(Order.class, orderId);
em.createQuery("select distinct p from Product p where :order not member of p.orders")...;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...