Spring Boot Rest API、JPA 实体、DTO,最好的方法是什么?

2024-05-04

我被分配了这个作业,只是为了练习,它变得非常漫长且具有挑战性,但它教会了我很多东西,主要是关于 lambda 和 JPA。

它是一个基本的Rest API,用于创建酒店、房间、客人、预订、客人类型、房间类型等。

我最初的问题是学习 JPA 关系、OneToOne、OneToMany 等、单向、双向等等。

我也在使用 PostgreSQL,使用"sping.jpa.hibernate.ddl-auto=create-drop(or update)",当我出于某种原因想要重新创建数据库时,根据需要进行更改。

因此,我非常高兴和兴奋使用我的新 @Annotations 来关联我的实体,并取回我需要的任何信息的列表,遇到了多个问题,在这里阅读了很多问题,解决了我的问题,但现在我遇到了一个新问题,但随后,开始质疑我的方法,也许我不应该把一切都留给 JPA。

让我告诉你我的意思。我将保持我的课程简短,只显示相关信息。

我有我的预订实体。

    @Data
    @Entity
    @Table(name = "reservation")
    public class Reservation {
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Long id;
      @OneToOne(cascade = CascadeType.ALL)
      @JoinColumn(name = "guest", referencedColumnName = "id")
      @JsonManagedReference
      @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
      private Guest guest;
      @OneToOne(cascade = CascadeType.ALL)
      @JoinColumn(name = "room", referencedColumnName = "id")
      private Room room;
      @ManyToMany(fetch = FetchType.LAZY,
          cascade = CascadeType.ALL)
      @JoinTable(name = "reservation_rooms",
          joinColumns = { @JoinColumn(name = "reservation_id" )},
          inverseJoinColumns = { @JoinColumn(name = "room_id") }
      )
      @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
      private List<ReservationRoom> roomList = new ArrayList<>();
    
      private LocalDate start_date;
      private LocalDate end_date;
      private Boolean check_in;
      private Boolean check_out;
    
      public void addRoom(Room room) {
        this.roomList.add(room);
      }
    
      public void removeRoom(Long id) {
        Room room = this.roomList.stream().filter(g -> g.getId() == id).findFirst().orElse(null);
        if (room != null) {
          this.roomList.remove(room);
        }
      }
    
    }

这是我的房间实体。

    @Data
    @Entity
    @Table(name = "room")
    public class Room {
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Long id;
      private String name;
      private String description;
      private Integer floor;
      @JsonProperty("max_guests")
      private Integer maxGuests;
      @ManyToOne(fetch = FetchType.LAZY)
      @JsonBackReference
      private Hotel hotel;
      @ManyToOne(fetch = FetchType.LAZY)
      @JsonProperty("type")
      @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
      private RoomType roomType;
    
      @Override
      public boolean equals(Object o) {
        if (this == o) {
          return true;
        }
        if (!(o instanceof Room)) {
          return false;
        }
        return id != null && id.equals(((Room) o).getId());
      }
    
      @Override
      public int hashCode() {
        return getClass().hashCode();
      }
    }

这是我的访客实体。


    @Data
    @Entity
    @Table(name = "guest")
    public class Guest {
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Long id;
      private String first_name;
      private String last_name;
      private String email;
      @ManyToOne(fetch = FetchType.LAZY)
      @JsonProperty("type")
      @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
      private GuestType guest_type;
      @ManyToMany(fetch = FetchType.LAZY,
          cascade =  {
              CascadeType.PERSIST,
              CascadeType.MERGE
          },
          mappedBy = "guestList"
      )
      @JsonBackReference
      @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
      private List<Reservation> reservationList = new ArrayList<>();
    
      public Guest(){}
    
      public Guest(Long id) {
        this.id = id;
      }
    
      public List<Reservation> getReservationList() {
        return reservationList;
      }
    
      public void setReservationList(List<Reservation> reservationList) {
        this.reservationList = reservationList;
      }
    }

一开始预订只能有一个房间,但要求改变了,现在可以有多个房间。因此,现在,客人列表需要链接到与预订关联的房间,而不是直接链接到预订。(我知道我有一位客人和一间房间,还有两者的列表,这是因为我使用单个客人作为预订名称,并使用单个房间作为“主”房间,但不要请不要介意)。

抛开 JPA 不谈,因为我遇到的每一个挑战都会问自己“JPAish 该怎么做?”,然后研究如何用 JPA 来做(这就是我了解 @ManyToMany 等注释的方式)。

我要做的只是创建一个新表,将预订与房间关联起来(这已经在我的实体中使用 JPA 完成),然后添加客人 ID。

因此,这个新表将与reservation_id、room_id 和guest_id 进行PK。非常简单,然后创建我的预订模型,其中有一个房间列表,而这个房间模型将有一个客人列表。简单的。

但我不想在当前的房间实体中添加宾客列表,因为我有一个端点,可能还有几个其他函数,它们会检索我的房间实体,并且我不想添加宾客列表,因为随着时间的推移,这个列表会变得越来越大,这是你不需要传递的信息。

因此,我做了一些研究,发现我可以使用 @Inheritance 或 @MappedSuperclass 扩展我的实体,并且我可以创建一个 Reservation_Room 模型,其中包括宾客列表并添加 Reservation_Room 列表,而不是我的预订中的房间列表实体,我真的不知道它是否可能。

话虽如此,在我继续研究并开始修改我的代码之前,我想知道这是否是正确的方法?或者我是否在这方面对 JPA 施加了太多压力?最好的方法是什么?可以在 JPA 上轻松实现/映射 3 id 关系表吗?

主要目标是让我的房间实体按原样公开,但是当将房间添加到预订中时,该房间还将有一个客人列表。我可以做这个 JPAish 吗?或者我应该创建一个新模型并根据需要填充信息?这并不能免除我创建 3 个 ids 表的责任。


根据您在此处所写的内容,我认为您可能会意识到持久性模型并不总是与您在 HTTP 端点中使用的表示模型相匹配。这通常是人们发现 DTO 的地方,您似乎也听说过。

DTO 应根据端点表示的需要进行调整/创建。如果您不想公开某些状态,则只需不要在 DTO 中为该数据声明 getter/字段即可。持久化模型应该简单地以某种方式设计,以便您可以按照您需要的方式持久化和查询数据。 DTO 和实体之间的翻译是一个单独的事情,对此我只能建议您给出Blaze-持久性实体视图 https://github.com/Blazebit/blaze-persistence#entity-view-usage a try.

我创建了这个库来允许 JPA 模型和自定义接口或抽象类定义的模型之间轻松映射,就像类固醇上的 Spring Data Projections 一样。这个想法是,您按照自己喜欢的方式定义目标结构(域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。

对于您的用例,使用 Blaze-Persistence Entity-Views 的 DTO 模型可能如下所示:

@EntityView(Reservation.class)
public interface ReservationDto {
    @IdMapping
    Long getId();
    GuestDto getGuest();
    List<RoomDto> getRooms();
}
@EntityView(Guest.class)
public interface GuestDto {
    @IdMapping
    Long getId();
    String getName();
}
@EntityView(Room.class)
public interface RoomDto {
    @IdMapping
    Long getId();
    String getName();
}

查询是将实体视图应用于查询,最简单的就是通过 id 进行查询。

ReservationDto a = entityViewManager.find(entityManager, ReservationDto.class, id);

Spring Data 集成允许您像 Spring Data Projections 一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

Page<ReservationDto> findAll(Pageable pageable);

最好的部分是,它只会获取实际需要的状态!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot Rest API、JPA 实体、DTO,最好的方法是什么? 的相关文章

随机推荐

  • Xml 瞬态无法工作 jaxb(Moxy)。?

    Xml 瞬态注释不适用于以下模型 XmlRootElement public class JdfValidation private String name private String dataType private String er
  • Python 3 - 如何从高维数据制作马赛克图?

    我有一个 pandas DataFrame data pd read csv r C data path demographics csv sep print data PersonID Married No of Children Sex
  • 将抽屉布局添加到主要活动中

    我创建了一个应用程序 它工作得很好 但现在我想在主活动中包含导航抽屉 我知道代码模板 但为此我需要创建新活动 我的问题是如何将抽屉布局包含到现有活动中仅包含 Recycler 视图和 fab 按钮 是否可以包含 抱歉这个大问题 您可以按照以
  • 注册方法的方法在引发事件时调用

    我有一个包含 20 个 PictureBox 控件的面板 如果用户单击任何控件 我希望调用面板中的方法 我该怎么做呢 public class MyPanel Panel public MyPanel for int i 0 i lt 20
  • Visual Studio 将 1.1 扩展为 1.1000000000000001

    至少对我来说 这是有史以来最奇怪的 Visual Studio 2010 行为 我正在开发 MVC3 项目 我从另一个项目 也包括 VS2010 MVC1 如果重要的话 复制了一行代码 如下所示 target height height 1
  • Unity InputField OnValueChanged事件显示InputField.text少一个字符

    我有一个InputField我用它作为搜索栏 我无法自动搜索OnValueChanged因为最初 文本字段将是 现在如果我输入任何字符a the inputField text还是 代替a因此 在添加下一个字符之前不会进行搜索 有没有办法在
  • 如何从 Web 应用程序访问仅限身份验证的 Twitter API 方法

    我有一个 iPhone 网络应用程序 它最终将在 PhoneGap 应用程序中运行 但现在我在 Safari 中运行它 该应用程序需要访问 Twitter 好友的推文 包括私人推文 所以我使用 Scribe 库实现了 OAuth 我成功地将
  • 创建具有负边框半径的按钮并在 Flutter 中对齐它们

    我想建立一个这样的布局 其中两个外部元素是按钮 而内部元素是 TextField 如何在 Flutter 中创建这样的布局 我的想法是使用绝对位置来对齐每个元素的左侧 并使用标高来处理重叠 但我不确定这是最好的方法 而且我不知道如何创建按钮
  • 使用 IOS 8 编辑时键盘间歇性消失

    我遇到过几个案例 测试人员报告说 每当他们开始在我的应用程序中的某些字段中输入内容时 键盘就会消失 我使用模拟器跟踪流程 并在手机上调试时 问题从未发生 然而 当我在不受限制的手机上尝试时 它的发生相当一致 这是一些相关的代码 所有这些都是
  • NetBeans 7.4 中的 SASS

    我在 Windows 7 64 位 上使用 NetBeans 7 4 这样我就安装了 Ruby200 x64 这样我就可以使用 Sass scss 到 css CSS 预处理器在 NetBeans 中的配置如下 C Ruby200 x64
  • Javascript匿名函数调用[重复]

    这个问题在这里已经有答案了 我正在阅读 Twitter 上的 JS 源代码 在提高我的 JS 知识库的过程中 当我遇到了调用匿名函数的奇怪方式时 function window jQuery 这有效 对于每个人来说 这是显而易见的 func
  • 使用组合来表示“is – a”关系时出现的问题

    我正在为人力资源系统开发系统 有会计员工和程序员员工 加入公司的第一个月 员工没有被赋予任何角色 一名员工可以同时担任会计师和程序员 我有一个由以下代码所示的设计 现在 我需要通过实现新功能来增强系统 解雇所有会计师 终止意味着将员工的状态
  • 仅当捏住单元格的 imageView 时,才可以在 UICollectionView 的自定义单元格中放大/缩小 UIImageView 吗?

    我有一个 CollectionView 它有一个自定义单元格 我想放大 缩小单元格中的 imageView 所以我在 CollectionView m 添加捏合手势 当我向 self collectionView 添加手势时 如下所示 se
  • Service Fabric:服务之间的调用有延迟?

    我们正在开发一个由多个不同服务组成的服务结构应用程序 我们的应用程序工作方式的一个关键部分是这些服务需要大量相互调用 直到最近我们增加了应用程序的负载并发现它的速度大大减慢时 我们才遇到任何问题 经过大量调查和对各种事情进行计时后 我们发现
  • 双端队列中元素的随机访问如何给出恒定的时间复杂度? [复制]

    这个问题在这里已经有答案了 双端队列为访问任何元素提供了恒定的复杂性 参考参数 https en cppreference com w cpp container deque 在 Vector 中 它总是恒定的复杂性 向量中第一个元素的地址
  • 我可以处理 XAML 中引发的异常吗?

    在我的 XAML 中 我通过绑定到 GetAll 属性来获取所有客户
  • 为什么leiningen启动时那么慢?

    我在用着lein repl在控制台中执行 clojure repl 当我运行它时 需要超过15秒 当我跑步时java cp clojure 1 6 0 jar clojure main 只需几秒钟 Why is lein repl太慢了 有
  • 让 SignalR 在 Android Studio 中工作的步骤

    我正在尝试带SignalR进入我的安卓工作室项目 我成功地按照教程进行操作SignalR 入门 http www asp net signalr overview getting started tutorial getting start
  • 将 DD-Mon-YYYY 转换为 DD/MM/YYYY

    我需要转换 dt of birth varchar 15 其格式为DD Mon YYYY to DD MM YYYY dt of birth在不同的表中指定 并且必须完成转换并将其存储在具有相同列名的另一个表中dt of birth Her
  • Spring Boot Rest API、JPA 实体、DTO,最好的方法是什么?

    我被分配了这个作业 只是为了练习 它变得非常漫长且具有挑战性 但它教会了我很多东西 主要是关于 lambda 和 JPA 它是一个基本的Rest API 用于创建酒店 房间 客人 预订 客人类型 房间类型等 我最初的问题是学习 JPA 关系