JPA的Embeddable Objects

本文介绍了如何在Java Persistence API (JPA)中使用@Embeddable注解来提高实体类的设计灵活性。通过一个具体的例子展示了如何将复合属性封装到一个单独的类中,并在实体类中作为单一属性引用。
转自[url]http://ealpha.iteye.com/blog/56440[/url]
在hibernate中实现自定义类型,只要实现UserType接口即可或者以Compnent的形式提供.JPA的@Embedded有点类似,通过此注释可以在你的Entity中使用一般的java对象,此对象需要用@Embeddable标注

举个简单例子:Person类有一个 name属性,name应该有firstName,lastName两个属性,一般的写法直接在entity中写两个属性:

private String firstName;

private String lastName;

我们可以用一个Name类来代替这样的写法,此类包含了firstName和lastName,如此一来,我们在entity只要这样写:

private Name name;

就可以了.那么Name类大概是什么样呢?如下:

package com.denny_blue.ejb3.entity;

import java.io.Serializable;

import javax.persistence.Embeddable;

@Embeddable
public class Name implements Serializable {
private String firstName;

private String lastName;
}
乐播投屏是一款简单好用、功能强大的专业投屏软件,支持手机投屏电视、手机投电脑、电脑投电视等多种投屏方式。 多端兼容与跨网投屏:支持手机、平板、电脑等多种设备之间的自由组合投屏,且无需连接 WiFi,通过跨屏技术打破网络限制,扫一扫即可投屏。 广泛的应用支持:支持 10000+APP 投屏,包括综合视频、网盘与浏览器、美韩剧、斗鱼、虎牙等直播平台,还能将央视、湖南卫视等各大卫视的直播内容一键投屏。 高清流畅投屏体验:腾讯独家智能音画调校技术,支持 4K 高清画质、240Hz 超高帧率,低延迟不卡顿,能为用户提供更高清、流畅的视觉享受。 会议办公功能强大:拥有全球唯一的 “超级投屏空间”,扫码即投,无需安装。支持多人共享投屏、远程协作批注,PPT、Excel、视频等文件都能流畅展示,还具备企业级安全加密,保障会议资料不泄露。 多人互动功能:支持多人投屏,邀请好友加入投屏互动,远程也可加入。同时具备一屏多显、语音互动功能,支持多人连麦,实时语音交流。 文件支持全面:支持 PPT、PDF、Word、Excel 等办公文件,以及视频、图片等多种类型文件的投屏,还支持网盘直投,无需下载和转格式。 特色功能丰富:投屏时可同步录制投屏画面,部分版本还支持通过触控屏或电视端外接鼠标反控电脑,以及在投屏过程中用画笔实时标注等功能。
<think>我们正在讨论JPA中的两个重要注解:@Embeddable和@ElementCollection。根据引用[4]和引用[5]提供的信息,我们可以这样理解:1.**@Embeddable**:用于标记一个类,表示这个类的实例可以作为另一个实体的嵌入部分(即值对象)。嵌入对象没有自己的生命周期,完全依赖于所属的实体。它们会被映射到拥有它们的实体表中,而不是单独的表。2.**@ElementCollection**:用于标记实体类中的一个集合属性(通常是基本类型或可嵌入对象的集合)。它会将集合中的元素映射到一个独立的表中,该表与实体表通过外键关联。当两者配合使用时,通常是为了表示一个实体包含多个值对象(例如,一个用户有多个电话号码,每个电话号码是一个包含类型和号码的值对象)。具体步骤:1.定义可嵌入类(值对象),用`@Embeddable`标注。2.在实体类中,定义一个集合(如List、Set)来包含这些可嵌入对象,并用`@ElementCollection`标注。3.使用`@CollectionTable`(可选)来指定生成的集合表的名称和连接列。###示例代码####步骤1:定义可嵌入类(值对象)```java@EmbeddablepublicclassPhoneNumber{privateStringtype;//如:home,work,mobileprivateStringnumber;//必须有无参构造函数(JPA要求)publicPhoneNumber(){}publicPhoneNumber(Stringtype,Stringnumber){this.type=type;this.number=number;}//Getter和Setter省略...}```####步骤2:在实体类中使用```java@EntitypublicclassUser{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateLongid;privateStringname;//使用@ElementCollection映射值对象集合@ElementCollection@CollectionTable(name="user_phone_numbers",//指定集合表的表名joinColumns=@JoinColumn(name="user_id")//指定外键列)privateList<PhoneNumber>phoneNumbers=newArrayList<>();//其他字段和方法...}```###数据库表结构-`user`表:存储用户基本信息-`id`(主键)-`name`-`user_phone_numbers`表:由`@ElementCollection`和`@CollectionTable`生成的表-`user_id`(外键,引用`user.id`)-`type`(来自`PhoneNumber`类)-`number`(来自`PhoneNumber`类)###关键点说明-**嵌入对象**:`PhoneNumber`类没有自己的标识(ID),它作为`User`实体的一部分被存储。-**集合表**:`user_phone_numbers`表是一个从表,通过`user_id`关联到主表`user`。-**操作**:当保存`User`实体时,其关联的`phoneNumbers`集合会自动保存到`user_phone_numbers`表中(级联操作)。###注意事项1.**默认表名和列名**:如果不使用`@CollectionTable`,JPA会使用默认名称(如`User_phoneNumbers`)。建议显式指定以保持一致性。2.**性能考虑**:大量元素集合可能导致性能问题(如N+1查询)。考虑使用`FetchType.LAZY`(默认就是延迟加载)。3.**值对象不可变**:设计为不可变对象更安全(避免副作用)。###相关问题1.在JPA中,如何为元素集合(`@ElementCollection`)添加索引以提高查询性能?2.如何处理元素集合的更新操作(如添加、删除单个元素)?3.使用`@ElementCollection`映射基本类型(如`List<String>`)与映射可嵌入对象有何区别?4.如何通过JPQL查询元素集合中的值对象属性?</think>### JPA 中 `@Embeddable` 和 `@ElementCollection` 配合使用详解 #### 核心概念 1. **`@Embeddable`** 用于定义**值对象(Value Object)**,表示该对象没有独立生命周期,完全依赖于所属的实体。值对象会被映射到**实体表内部**(非独立表)[^2][^4]。 2. **`@ElementCollection`** 用于映射**值对象集合**,JPA 会自动创建**独立的子表**存储这些集合元素,并通过外键关联主实体[^5]。 #### 配合使用场景 当实体需要包含**多个复杂值对象**时(如用户的多个地址、多个电话号码),两者配合可实现: - 值对象定义 → `@Embeddable` - 值对象集合 → `@ElementCollection` --- ### 完整示例 #### 1. 定义值对象(`@Embeddable`) ```java @Embeddable public class Address { private String street; private String city; private String zipCode; // 必须有无参构造函数(JPA要求) public Address() {} public Address(String street, String city, String zipCode) { this.street = street; this.city = city; this.zipCode = zipCode; } // Getters & Setters } ``` #### 2. 实体中使用值对象集合(`@ElementCollection`) ```java @Entity public class User { @Id @GeneratedValue private Long id; private String name; // 映射值对象集合 @ElementCollection @CollectionTable( name = "user_addresses", // 自定义子表名 joinColumns = @JoinColumn(name = "user_id") // 外键列 ) private List<Address> addresses = new ArrayList<>(); // 其他字段和方法... } ``` #### 3. 数据库结构 | **表名** | **字段** | **说明** | |-----------------|-----------------------|-----------------------------| | `user` | `id` (PK) | 主实体表 | | | `name` | | | `user_addresses`| `user_id` (FK) | 外键引用`user.id` | | | `street` | 来自`Address`的值对象字段 | | | `city` | | | | `zip_code` | | --- ### 关键特性 1. **级联操作** 保存 `User` 实体时,其关联的 `addresses` 集合会自动插入子表: ```java User user = new User("Alice"); user.addAddress(new Address("Main St", "New York", "10001")); userRepository.save(user); // 自动保存地址到子表 ``` 2. **查询方式** - 通过主实体访问: ```java User user = userRepository.findById(1L); List<Address> addresses = user.getAddresses(); ``` - JPQL 直接查询子表: ```java @Query("SELECT a FROM User u JOIN u.addresses a WHERE a.city = :city") List<Address> findByCity(String city); ``` 3. **自定义映射** 通过 `@AttributeOverride` 修改子表列名: ```java @ElementCollection @CollectionTable(name = "user_addresses") @AttributeOverride( name = "zipCode", column = @Column(name = "postal_code") // 自定义列名 ) private List<Address> addresses; ``` --- ### 与相关注解对比 | **注解** | 作用范围 | 存储方式 | 典型用例 | |------------------------|------------------|----------------|----------------------------| | `@Embeddable` | 单个值对象 | 主表内部 | 用户详细资料(非集合)[^2] | | `@ElementCollection` | 值对象集合 | 独立子表 | 用户多个地址/电话[^4] | | `@OneToMany` | 实体集合 | 独立表(实体) | 订单-订单项(有独立ID) | --- ### 最佳实践 1. **值对象设计原则** - 保持值对象**不可变**(字段用 `final` + 全参构造器) - 避免包含业务逻辑 2. **性能优化** 大型集合使用延迟加载: ```java @ElementCollection(fetch = FetchType.LAZY) ``` 3. **DDL 自动生成** 配合 `spring.jpa.hibernate.ddl-auto=update` 可自动创建表结构[^2]。 --- ### 相关问题 1. 如何在 `@ElementCollection` 的子表中添加唯一约束? 2. 使用值对象集合时,如何实现高效的批量更新操作? 3. `@Embeddable` 对象能否包含对其他实体的引用?会有什么影响? 4. 如何通过 JPA 规范查询(Specification)动态过滤值对象集合的属性? > 示例源码参考:[Spring Data JPA 实战 - 可嵌入对象和元素集合](https://example.com/jpa-embeddables)[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值