Как реализовать сущность, содержащую два списка сущностей одного типа в Spring Data - PullRequest
0 голосов
/ 12 октября 2018

У меня есть сущность Order.Он содержит список стеклянных деталей и список не стеклянных деталей.Часть представляет собой единое целое с атрибутом PartType (стекло / не стекло).Это возможно с Spring Data?Как?Я использую Spring Boot 1.3.1.RELEASE с Hibernate.

@Entity
@Table(name="order")
public class Order {

    ...

    @OneToMany(...)
    private List<Part> glassParts;

    @OneToMany(...)
    private List<Part> otherParts;
}

@Entity
@Table(name="part")
public class Part {

  ...

  @Column(...)
  private PartType partType;

  @Column(...)
  private String code;

  @Column(...)
  private String description;
}

1 Ответ

0 голосов
/ 14 октября 2018

Я считаю, что в вашем случае не стоит создавать два списка.Для достижения результата есть два общих подхода.Первый заключается в создании двунаправленного отношения и реализации слоев Repository и Manager с соответствующими условиями:

@Entity
@Table(name="order")
public class Order {

    ...

    @OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = { ... })
    private List<Part> parts;
}

@Entity
@Table(name="part")
public class Part {

  ...

  @JoinColumn(name = "r_order_id", referencedColumnName = "id")
  @ManyToOne(...)  
  private Order order;
  @Column(...)
  private PartType partType;

  @Column(...)
  private String code;

  @Column(...)
  private String description;
}

public interface PartInterface implements CrudRepository<Part, Long> {

  List<Part> findByOrderIdAndPartType(Long orderId, PartType partType);
}

@Component
public class PartManager {

  @Autowired
  private PartInterface partInterface;

  public List<Part> getGlassPartsByOrderId(Long orderId) {
    return List<Part> partInterface.findByOrderIdAndPartType(orderId, PartType.GLASS);
  }

  public List<Part> getNonGlassPartsByOrderId(Long orderId) {
    return List<Part> partInterface.findByOrderIdAndPartType(orderId, PartType.NON_GLASS);
  }
}

Второй - для фильтрации всех частей заказа по типу:

public interface OrderInterface implements CrudRepository<Order, Long> {

  @Override
  Order findOne(Long orderId);
}

@Component
public class OrderManager {

  @Autowired
  private OrderInterface orderInterface;

  public List<Part> getGlassPartsByOrderId(Long orderId) {    
    return getOrderParts(orderId).stream().filter(part -> Objects.equals(PartType.GLASS, part.getPartType())).collect(Collectors.toList());    
  }

  public List<Part> getNonGlassPartsByOrderId(Long orderId) {
    return getOrderParts(orderId).stream().filter(part -> Objects.equals(PartType.NON_GLASS, part.getPartType())).collect(Collectors.toList());    
  }

  private List<Part> getOrderParts(Long orderId) {
    Order order = orderInterface.findOne(Long orderId);
    if (Objects.isNull(order) || Objects.isNull(order.getParts())) {
      return Collections.emptyList();
    } else {
      return order.getParts();
    }
  }
}

На самом деле есть еще один вариант - фильтровать детали внутри сущности на лету:

@Entity
@Table(name="order")
public class Order {

    @OneToMany(...)
    private List<Part> parts;

    public List<Part> getGlassParts{
      if (Objects.nonNull(parts)) {
        return parts.stream().filter(part -> Objects.equals(PartType.GLASS, part.getPartType())).collect(Collectors.toList());
      } else {
        return Collections.emptyList();
      }
    }

    public List<Part> getNonGlassParts{
      if (Objects.nonNull(parts)) {
        return parts.stream().filter(part -> Objects.equals(PartType.NON_GLASS, part.getPartType())).collect(Collectors.toList());
      } else {
        return Collections.emptyList();
      }
    }
}

ОБНОВЛЕНИЕ Поскольку вы используете Hibernate, естьORM-зависимая опция для получения желаемого результата, это аннотация @JoinColumnOrFormula, которая доступна только для Hibernate:

@Entity
@Table(name="order")
public class Order {

    @OneToMany(...)
    @JoinColumnOrFormula(
      column = @JoinColumn(name = "id", referencedColumnName = "r_order_id", insertable = false, updatable = false)
      ,formula = @JoinFormula(value = PartType.GLASS_STR_VALUE, referencedColumnName = "partType"))
    private List<Part> glassParts;

    @OneToMany(...)
    @JoinColumnOrFormula(
      column = @JoinColumn(name = "id", referencedColumnName = "r_order_id", insertable = false, updatable = false)
      ,formula = @JoinFormula(value = PartType.NON_GLASS_STR_VALUE, referencedColumnName = "partType"))
    private List<Part> nonGlassParts;    
}

Обратите внимание, что параметр value внутри@JoinFormula предложение должно быть String

...