Java 在JPA中持久化非原始数据

Java 在JPA中持久化非原始数据,java,mysql,spring,hibernate,jpa,Java,Mysql,Spring,Hibernate,Jpa,我正在创建一个需要与数据库交互的程序。这是一个简单的库存管理系统,所以实体是“物品”和“顾客” 编辑:这是一个使用Spring引导和Spring数据JPA的Vaadin应用程序 首先,为了简洁起见,我将从我的两个类开始,省略getter/setter @Table(name="item") @Entity public class Item implements Serializable, Cloneable { @Id @GeneratedValue(strategy=Ge

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

编辑:这是一个使用Spring引导和Spring数据JPA的Vaadin应用程序

首先,为了简洁起见,我将从我的两个类开始,省略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;
    }
用户表

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?
用户项目历史记录表 :这将从用户表中提取id、姓名、电子邮件,然后从项目表中提取id、签出日期、到期日期

项目用户历史记录表:与上表结构类似

提前谢谢。

好的,开始吧

我假设您正在使用SpringBoot构建应用程序,Hibernate作为您的ORM,并且可能使用某种数据库或关系数据库(MySQL)

关于数据库设计:

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

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

2) 丢失checkedOutItems数组以及itemHistory列表。首先,应该使用集合而不是数组对关系进行建模。其次,你不需要这两个。 您永远不会以这种方式存储checkedOutItems或itemHistory。而是创建一个
列表项
,该列表项将在描述关系时存储Patreon项(以下是一些示例:)

3) 同样,对于项目实体,您需要丢失历史数组。这里唯一需要的是对所属实体的引用(在本例中是Patreon),从而完成关系的许多方面

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

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

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

关于你的问题:

问题1:是的,我明白了。详见上文

问题1.2:没有阵列不是。列表或更好的集合更适合

问题1.3:是的。第一个是在关系数据库中使用的JPA注释 数据库,而第二个是Spring数据特定的注释 由非此类型的数据库和框架使用 (关系)或没有定义标准持久性API(如 JPA)。对于NonNull和NotNull,它们与第一个基本相同 一个实际上取代了后一个(已经完成的事情) 经常)。我看到的唯一区别是目标。你可以为我读书 详情如下:

问题2:是的。见上文

问题3:通过一点巧妙的设计,我认为没有必要再做更多,但是 嘿,如果你觉得这对你有帮助,为什么不呢。只是别杀得太多
设计及其复杂性

昨天我花了很长时间在脑子里思考一个解决方案。 我对两个班都做了你提到的改变。Long是一个对象,Long是一个原语,您可以序列化Long,这就是您建议我使用它的原因吗

我继续拉小提琴来测试我的想法,下面是我的想法。它可以按我所希望的方式工作,但是我需要在我的存储库中实现它。。像回购、结帐(物品、顾客)这样的东西就足够了吗?至于其他一切,比如填充一个列表供客户端查看,从现在开始主要是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;

您是否尝试过每节课一个文件?春天使用了很多自反性。这可能就是问题所在。这看起来像是考试,不是吗?不,是为了工作。此外,赞助人和物品是各自独立的类别。感谢您的热烈响应,不幸的是,这带来了更多的问题:)长期使用有什么好处?至于跟踪项目的历史记录,什么是一种明智的方法?我已修改实体以丢失阵列数据。如果我错了,请纠正我,但由于它是一种“一对多”关系,列表会加载用户引用的项目集合吗?内部联接是否适用,或者我是否需要根据需要创建一个引用项目/用户值的新表?Long是一个对象,可以为null。龙是原始的。它不能为null。@GweltazNiquel是的,但在表中的键上下文中,列定义默认为不可为null,并且该值由基础ORM自动生成和管理,无论它是
Long
还是
Long
,都不重要。你是对的,tue ORM不介意它是长的还是长的,但是如果您传递了一个为null的Long,那么它将触发一个异常,因为底层数据库中有一个notnull约束。自动生成策略也不是一个约束,它并不意味着您不能以其他方式设置它…@GweltazNiquel是的,只要列定义不可为null,否则它应该可以正常运行。老实说,我确实希望抛出异常,而不是退回到原语类型的默认值。此外,这还可能导致完整性约束异常。