我正在从事一个项目,并希望在其中实施Hibernate。我已经看过许多讨论关系的视频,并给出了诸如“客户订单”之类的示例,在该示例中,一个客户可以拥有许多订单,但“订单”仅指一个客户。或者,学生-课程,学生可以参加许多课程,反之亦然。在我的特定情况下,我有一个Customer表和Salutation表,我想确保使用了一套标准的称呼语,所以我有以下内容:
我不确定如何设置这种类型的关系。在我所看到的所有示例中,您都将在Customer表中放置对Salutation对象的引用,但这似乎没有任何意义。下面我的客户表中的称呼字段是int类型。那么如何为这样的实例形成关系?谢谢您的帮助!
答案 0 :(得分:1)
正如您所说的,您正在学习并且没有标记hibernate
或spring
之类的spring-boot
以外的其他标记,请让我详细介绍一下您的工作。
让我们以Cart and Items
表为例。 。 。 。 。我们将外键约束用于一对多映射:
CREATE TABLE `Cart` (
`cart_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`cart_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
CREATE TABLE `Items` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`cart_id` int(11) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `cart_id` (`cart_id`),
CONSTRAINT `items_ibfk_1` FOREIGN KEY (`cart_id`) REFERENCES `Cart` (`cart_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
如果您使用的是springboot,则可以跳过配置步骤,因为它仅通过一个依赖项进行了预配置。
Maven依赖项
然后,我们将Hibernate和H2驱动程序依赖项添加到我们的pom.xml文件中。 Hibernate依赖项使用JBoss日志记录,它会自动添加为传递性依赖项:
请访问Maven中央存储库以获取最新版本的Hibernate和H2依赖项。
休眠配置
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">org.h2.Driver</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.connection.url">
jdbc:h2:mem:spring_hibernate_one_to_many</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.show_sql">true</property>
</session-factory>
</hibernate-configuration>
HibernateAnnotationUtil类
private static SessionFactory sessionFactory;
private SessionFactory buildSessionFactory() {
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().
configure("hibernate-annotation.cfg.xml").build();
Metadata metadata = new MetadataSources(serviceRegistry).getMetadataBuilder().build();
SessionFactory sessionFactory = metadata.getSessionFactoryBuilder().build();
return sessionFactory;
}
public SessionFactory getSessionFactory() {
if(sessionFactory == null) sessionFactory = buildSessionFactory();
return sessionFactory;
}
模型
与映射相关的配置将使用模型类中的JPA注释完成:
@Entity
@Table(name="CART")
public class Cart {
//...
@OneToMany(mappedBy="cart")
private Set<Items> items;
// getters and setters
}
请注意,@OneToMany批注用于定义Items类中的属性,该属性将用于映射mappingBy变量。这就是为什么我们在Items类中有一个名为“ cart”的属性的原因:
@Entity
@Table(name="ITEMS")
public class Items {
//...
@ManyToOne
@JoinColumn(name="cart_id", nullable=false)
private Cart cart;
public Items() {}
// getters and setters
}
实际操作
在测试程序中,我们正在使用main()方法创建一个类,以获取Hibernate Session并将模型对象保存到数据库中,以实现一对多关联:
sessionFactory = HibernateAnnotationUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created");
tx = session.beginTransaction();
session.save(cart);
session.save(item1);
session.save(item2);
tx.commit();
System.out.println("Cart ID=" + cart.getId());
System.out.println("item1 ID=" + item1.getId()
+ ", Foreign Key Cart ID=" + item.getCart().getId());
System.out.println("item2 ID=" + item2.getId()
+ ", Foreign Key Cart ID=" + item.getCart().getId());
这是我们测试程序的输出:
Session created
Hibernate: insert into CART values ()
Hibernate: insert into ITEMS (cart_id)
values (?)
Hibernate: insert into ITEMS (cart_id)
values (?)
Cart ID=7
item1 ID=11, Foreign Key Cart ID=7
item2 ID=12, Foreign Key Cart ID=7
Closing SessionFactory
@ManyToOne
批注
如上所述,我们可以使用many-to-one
批注指定@ManyToOne
关系。 many-to-one
映射意味着此实体的许多实例都映射到另一个实体的一个实例–一个购物车中的许多物品。
@ManyToOne 注释也使我们能够创建双向关系。我将进一步详细介绍。
不一致和所有权
现在,如果购物车引用了商品,但商品又没有引用购物车,则我们的关系将是单向的。这些对象也将具有自然的一致性。
但是,在我们的案例中,这种关系是双向的,从而可能导致不一致。
让我们想象一下这样一种情况:开发人员想要将item1添加到购物车中,并将item2添加到cart2,但是犯了一个错误,从而使cart2和item2之间的引用不一致:
Cart cart1 = new Cart();
Cart cart2 = new Cart();
Items item1 = new Items(cart1);
Items item2 = new Items(cart2);
Set<Items> itemsSet = new HashSet<Items>();
itemsSet.add(item1);
itemsSet.add(item2);
cart1.setItems(itemsSet); // wrong!
如上所示,item2引用了cart2,而cart2没有引用item2,这很糟糕。
Hibernate如何将item2保存到数据库?物品2 foreign key
是否引用购物车1或购物车2?
我们使用关系的拥有方的想法解决了这种歧义-属于拥有方的引用具有优先权,并保存到数据库中。
作为拥有方 最好将多对一方标记为拥有方。
换句话说,Item是拥有方,而Cart是相反方,这正是我们之前所做的。
那么,我们如何实现这一目标?
通过在Cart类中包含mappingBy属性,我们将其标记为反面。
同时,我们还使用@ManyToOne注释Items.cart字段,使Items成为拥有方。
回到我们的“不一致”示例,现在,Hibernate知道item2的引用更为重要,并且会将item2的引用保存到数据库中。
让我们检查一下结果:
item1 ID=1, Foreign Key Cart ID=1
item2 ID=2, Foreign Key Cart ID=2
推车为拥有方
也可以将一对多的一面标记为拥有面,将多对一的面标记为反面。
尽管不建议这样做,但让我们继续尝试一下。
下面的代码片段显示了一对多方作为拥有方的实现:
public class ItemsOIO {
// ...
@ManyToOne
@JoinColumn(name = "cart_id", insertable = false, updatable = false)
private CartOIO cart;
//..
}
public class CartOIO {
//..
@OneToMany
@JoinColumn(name = "cart_id") // we need to duplicate the physical information
private Set<ItemsOIO> items;
//..
}
请注意我们如何删除mapedBy元素并将多对一@JoinColumn设置为可插入且可更新为false。
如果我们运行相同的代码,结果将相反:
item1 ID=1, Foreign Key Cart ID=1
item2 ID=2, Foreign Key Cart ID=1
如上所示,现在item2属于购物车。
希望从学习前瞻就足够了。
答案 1 :(得分:0)
我认为您必须了解各种关系。
您使用的图显示在另一个实体中外部化的one-to-one relationship。您可以这样做,但是没有什么可以强迫您这样做。大多数时候情况都很好。自由。
在我的特定情况下,我有一个Customer表和一个Salutation表,我想在其中确保标准的称呼集
您输入的文字告诉我您有1个客户和许多可能的称呼。如果网络用户只能选择其中之一,那么您的图表就很好。
否则,如果网络用户可以选择许多选项,则必须查看one-to-many relationship。
Many-to-many relationships也已经存在,但您不在那种用例中。