【问题标题】:Persist non-primitive data in JPA在 JPA 中保留非原始数据
【发布时间】:2018-06-14 20:05:08
【问题描述】:

我正在创建一个需要与数据库交互的程序。这是一个简单的库存管理系统,所以实体是“Item”和“Patron”。

编辑:这是一个使用 Spring Boot 和 Spring Data JPA 的 Vaadin 应用程序

首先,我将从我的 2 个类开始,为简洁起见省略 getter/setter。

@Table(name="item")
@Entity 
public class Item implements Serializable, Cloneable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long barcode;
    @NotNull
    private String name, type;
    @NotNull
    private boolean isAvailable;
    @Nullable
    private boolean isLate;
    @Nullable
    private String notes;
    @Nullable
    private Patron currentPatron;
    @Nullable
    private Patron[] history;
    @Nullable
    private Date checkOutDate, dueDate;

    public Item() {}

    public Item(long barcode, String name, String type, boolean isAvailable) {
        this.barcode = barcode;
        this.name = name;
        this.type = type;
        this.isAvailable = isAvailable;
    }

    public Item(long barcode, String name, String type, String notes, boolean isAvailable) {
        this.barcode = barcode;
        this.name = name;
        this.type = type;
        this.notes = notes;
        this.isAvailable = isAvailable;
    }

    public Item(long barcode, String name, String type, String notes, boolean isAvailable, Date checkOutDate, Date dueDate, boolean isLate, Patron currentPatron, Patron[] history) {
        this.barcode = barcode;
        this.name = name;
        this.type = type;
        this.notes = notes;
        this.isAvailable = isAvailable;
        this.checkOutDate = checkOutDate;
        this.dueDate = dueDate;
        this.isLate = isLate;
        this.currentPatron = currentPatron;
        this.history = history;
    }
}

@Entity
@Table(name="patron")
public class Patron {
    @Id
    private long id;
    @NotNull
    private String name, email;
    @Nullable
    private Item[] checkedOutItems;
    @Nullable
    private List<Item> itemHistory;
    @Nullable
    private boolean owesFines;
    @Nullable
    private int finesOwed;

    public Patron() {}

    public Patron(long id, String name, String email, boolean owesFines) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.owesFines = owesFines;
    }

    public Patron(long id, String name, String email, Item[] checkedOutItems, List<Item> itemHistory, boolean owesFines, int finesOwed) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.checkedOutItems = checkedOutItems;
        this.itemHistory = itemHistory;
        this.owesFines = owesFines;
        this.finesOwed = finesOwed;
    }

在实践中,通过使用 MSR 扫描其校园 ID 来实例化赞助人对象。然后,该数据填充顾客类别的姓名、电子邮件和 ID 字段。

在结账时,顾客会先用 MSR 刷卡(系统会确认他们在数据库中,如果没有则添加)。 在他们的磁条被扫描后,他们想要的物品的二维码就会被扫描,这样我们就可以将该物品与他们联系起来。

当一个项目被借给顾客时,我们需要从顾客表中获取他们的 idnameemail,然后填充其余变量:check_out_datedue_date 等。

一个读者可以借出许多单册,但一个读者只能借出一个单册。这是否建立了OneToMany 关系?赞助人 -> 物品(

我的思考过程如下:

用于赞助对象 有一个 Items 数组来存储他们当前拥有的项目的条形码。 有一个项目数组列表来存储有关顾客拥有它以及何时拥有它的信息 List&lt;Item&gt; history,这样代码就像 history.addToFront(something) 一样简单

对于项目对象 有一个赞助人对象,看看谁拥有它 有一个顾客数组列表来查看它被签出的所有时间

Q1:将数组和列表作为两个类的实例数据是否多余?

Q1.2:对象数组和对象列表是否适合此类场景的数据结构?

Q1.3:将javax.persistence.*;org.springframework.data.annotation.*; 用于ID 之类的东西有区别吗?import javax.validation.constraints.NotNull;import org.springframework.lang.NonNull; 之间有区别吗

Q2:这会在 Patron 和 Items 之间产生OneToMany 关系吗?

Q3:为了实现这一点,我相信我的数据库中需要一些额外的表。我在想这样的事情:(我意识到在实现新架构时我需要包含适当的弹簧注释)

项目表

create table item(barcode int(10) primary key, name varchar(64) not null, type varchar(64) not null, availability boolean, is_late boolean, note varchar(255), check_out_date Datetime, due_date Datetime); #foreign keys for currentPatron and Patron History

顾客表

create table patron(id int(10) primary key, name varchar(64) not null, email varchar(64) not null, owes_fines boolean, fines_owed int); #foreign key to item table?

Patron_Item_History 表 :这会从 Patient 表中提取 id、name、email,然后从 item 表中提取 id、check_out_date、due_date

Item_Patron_History 表:与上表类似的结构?

提前谢谢你。

【问题讨论】:

  • 你尝试过每个班级一个文件吗? Spring 使用了很多反射性。这可能是问题所在。这看起来像是一场考试,不是吗?
  • 不,是为了工作。此外,patron 和 item 是它们自己独立的类。

标签: java mysql spring hibernate jpa


【解决方案1】:

好的,去吧,

我假设您正在使用 Spring Boot、Hibernate 作为您的 ORM 以及可能某种类型或关系数据库 (MySQL) 来构建您的应用程序。

关于数据库设计:

是的,这里的 Patreon 对象是与 Item 实体具有 OneToMany 关系的拥有实体(因为一个 Patreon 可能有 N 个对象)。 您的 Patreon 实体可以进行以下重新设计:

1) 尝试使用非原始类型,尤其是表键(长 id -> 长 id)。

2) 丢失checkedOutItems 数组以及itemHistory 列表。首先,关系应该使用集合而不是数组来建模。其次,你不需要这两个。 您永远不会以这种方式存储checkedOutItems 或itemHistory。而是创建一个 List&lt;Item&gt; items 来存储 Patreon 项目,同时描述关系(这里有一些示例:http://www.baeldung.com/hibernate-one-to-many

3) 再次使用 Item 实体,您需要丢失历史数组。您唯一需要的是对拥有实体(在本例中为 Patreon)的引用,从而完成关系的 ManyToOne 方面。

4) 请注意,日期字段应使用 @Temporal 进行注释,同时提供正确的类型(您可以阅读更多信息)。

5) 通常项目类应该重新设计。

5) 完成上述所有操作并假设您使用的是 Spring,您可以创建一个存储库,您可以使用该存储库查询 Patreon 对象,从而检索对象及其相关实体(项目)。

关于您的问题:

Q1:是的,它看到了。有关更多信息,请参见上文。

Q1.2:没有数组不是。列表或更好的集合更适合。

Q1.3:是的。第一个是关系中使用的 JPA 注释 数据库,而第二个是 Spring Data 特定的注释 由不属于这种类型的数据库和框架使用 (关系)或没有定义标准的持久性 API(如 JPA)。对于 NonNull 和 NotNull 与第一个大致相同 一个实际上取代了后一个(已经完成的事情 经常)。我看到的唯一区别是目标。你可以阅读 更多在这里: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/lang/NonNull.html https://docs.oracle.com/javaee/7/api/javax/validation/constraints/NotNull.html

Q2:是的。见上文。

Q3:通过一些巧妙的设计,我认为不需要更多,但是 嘿,如果你觉得它会帮助你,为什么不呢。只是不要过度杀伤 设计及其复杂性

【讨论】:

  • 感谢您的大力响应,不幸的是,这带来了更多问题:) 使用 Long 而不是 long 有什么优势?至于跟踪项目的历史记录,这样做的明智方法是什么?我修改了我的实体以丢失数组数据。如果我错了,请纠正我,但由于它是 OneToMany 关系,因此 List 加载了顾客引用的项目集合?内部联接是否适用,或者我是否需要根据需要创建一个引用来自项目/赞助人的值的新表?泰。
  • Long 是一个对象,可以为空。 long 是一个原始的。不能为空。
  • @GweltazNiquel 是的,但是在表中的键的上下文中,列定义默认为不可为空,并且该值由底层 ORM 自动生成和管理,这无关紧要不管是Long 还是long
  • 你说得对,周二 ORM 不介意它是 Long 还是 long 但是如果你传递一个为空的 Long,那么它将触发一个异常,因为底层存在非空约束数据库。自动生成策略也不是一个约束,这并不意味着你不能设置它...
  • @GweltazNiquel 是的,只要列定义不可为空,否则它应该可以正常运行。老实说,我确实更喜欢抛出异常而不是回退到原始类型的默认值。除此之外,还可能导致完整性约束异常。
【解决方案2】:

昨天我花了很长时间在脑海中思考解决方案。 我对这两个类都做了你提到的改变。 Long 是一个对象,long 是一个基元,你可以序列化 Long,这就是你推荐我使用它的原因吗?

我继续小提琴以测试我的想法,这就是我想出的。它可以按我的意愿工作,但是我需要在我的存储库中实现它。像 repo.checkout(item, parents) 这样的东西就足够了吗?至于其他的东西,比如填充一个列表供客户端查看,从这里开始主要是java逻辑吗?

无论如何,这是我的解决方案!

create table item (
    barcode bigint not null auto_increment primary key,
    name varchar(20) not null,
    type varchar(20) not null,
    is_available boolean not null,
    is_late boolean null,
    notes varchar(255) null,
    check_out_date datetime null,
    due_date datetime null
    #create index idx_barcode (barcode));

create table patron (
    trinity_id bigint not null primary key,
    name varchar(30) not null,
    email varchar(20) not null,
    owes_fines boolean not null,
    fines_owed int null
    #create index idx_trinity_id (trinity_id));

create table checked_out_items (
    ref_id bigint primary key auto_increment not null,
    patron_id bigint not null,
    item_id bigint not null,
    item_available boolean not null,
    item_check_out_date datetime null,
    item_due_date datetime null);

alter table checked_out_items
    add constraint fk_patron_id
    foreign key (patron_id) references patron(trinity_id),
    add constraint fk_item_id
    foreign key (item_id) references item(barcode)
    #add constraint fk_item_available
    #add constraint fk_check_out_date
    #add constraint fk_due_date
    #foreign key (item_available references item(is_available)
    #foreign key (item_check_out_date) references item(check_out_date)
    #foreign key (item_due_date) references item(due_date)
    on update cascade
    on delete cascade;     


insert into patron values(0000000,'Test Erino','test@erino.edu',0,null);
insert into item values(1,'Chromebook','Laptop',0,null,null,null,null);

insert into  checked_out_items(patron_id,item_id,item_available,item_check_out_date,item_due_date)
select patron.trinity_id,item.barcode,item.is_available,item.check_out_date,item.due_date
from patron
inner join item;

最后:

select * from item;
select * from patron;
select * from checked_out_items;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-03
    • 2023-02-18
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    • 2019-11-19
    相关资源
    最近更新 更多