当该列属于Spring中的复合主键时如何按一列过滤

Posted

技术标签:

【中文标题】当该列属于Spring中的复合主键时如何按一列过滤【英文标题】:How to filter by one column when that column belongs to a composite primary key in Spring 【发布时间】:2019-05-11 21:05:45 【问题描述】:

拥有这样的 DAO:

@Entity
@Table(name="booking")

public class BookingObject implements Serializable

private static final long serialVersionUID = 1L;

@EmbeddedId
private CompositeId compositePK;
private LocalDate init_date;
private LocalDate end_date;
private int confirmation;
// getters and setters 

和复合主键:

@Embeddable
public class CompositeId implements Serializable

private static final long serialVersionUID = 1L;
@NotNull
private String guest;
@NotNull
private String idhousing;
//getters and setters

所以我现在可以从我的@RestController 拨打findById(new CompositeId(guest, idhousing));。 问题是:如果我想按复合主键的列之一进行过滤,比如 guest。

我不能这样做 findByguest,因为我的 DAO BookingObject 中不再存在来宾。我怎样才能得到“给我所有来宾等于...的行”的结果

【问题讨论】:

select b from BookingObject b where b.compositePK.guest = :guest。确实,真的,您应该避免使用复合函数 ID 并使用自动生成的技术 ID。 @JBNizet 和自动生成的 ID 会生成复合主键吗? 不,我的意思是您应该避免使用复合函数 ID。 @JBNizet 问题是,如果没有复合主键 guest 和 id_house,我将无法多次预订一个特定的房子。想象客人是主键。那么一个用户不能预订多于一个房子,这不符合逻辑,因为他可以预订下周的房子,下个月的另一个。另一方面,如果 id_house 是主键,则不能多次预订。房子可以在下周和一年内预订。希望你能理解我的问题。 我从来没有建议你使用guest或house作为PK。我建议使用自动生成的技术 ID。顺便说一句,你的 PK 设计是错误的:同一个客人不能在两个不同的日期预订同一个房子,因为 [guest, house] 是 PK,因此必须是唯一的。 【参考方案1】:

另一种方法是创建autoincremental key。它是一个整数,当在表中插入新行时会自动递增。这样就不需要复合主键了。唯一的问题是用户可以在同一日期无限次预订同一所房子。但是可以在您的 servlet 中实现一些逻辑,以检查该用户是否已经预订了该房子。 参考:w3schools autoincrement

【讨论】:

【参考方案2】:

你可以试试 findByExample

    CompositeId compId= new CompositeId();
    compId.setGuest(guestVal);

    BookingObject bookingObj= new BookingObject ();
    bookingObj.setCompositeId(compId);
    Example<BookingObject> bookExample = Example.of(bookingObj);
    List<BookingObject>  objList=repository.findAll(bookExample);

【讨论】:

【参考方案3】:

您可以通过在存储库类中声明一个查询方法来做到这一点,例如

List<BookingObject> findByCompositePKGuest(String guest);

并使用此方法从您的控制器获取数据。

该方法以标准 JPA 格式编写。方法名称被解析为对象和字段的概念,并在后台转换为实际的 SQL 查询。

更多参数是这样的

List<BookingObject> findByCompositePKGuestAndCompositePKIdhousing(String guest, String idhousing);

findByCompositePKGuestAndCompositePKIdhousing 转换为 -> findBy + compositePK.guest + And + compositePK.idhousing


另一种选择是通过示例使用 Spring JPA 过滤器

在存储库类中声明findAll(Example)方法

List<BookingObject> findAll(Example<BookingObject> bookingObject);

然后像这样从控制器调用这个方法

BookingObject bookingObject = new BookingObject();
CompositeId compositeId = new CompositeId();
compositeId.setGuest(guest);
bookingObject.setCompositeId(compositeId);
Example<BookingObject> bookingObjectExample = Example.of(bookingObject);
List<BookingObject> bookingObjectList = bookingRepository.findAll(bookingObjectExample);

请参阅此link 以获得更详细的答案

【讨论】:

以上是关于当该列属于Spring中的复合主键时如何按一列过滤的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate:insertable = false,updatable = false 属于涉及外键的复合主键星座中的哪里?

如何在 Room 持久库中使用复合主键时使主键自动递增?

如何在按另一列排序时按一列过滤?

MS SQL 2008 设置主键 该列值为啥还能重复

制作复合主键时,何时会被视为 OVERKILL?

ORA-01400: 当使用 @onetomany 映射并且在子端具有复合主键时,无法将 NULL 插入