Какую бы аннотацию использовал, чтобы игнорировать класс как сущность?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Аннотации для игнорирования класса как сущности в JPA/Hibernate
При работе с JPA и Hibernate есть несколько способов игнорировать класс, чтобы он не рассматривался как сущность (entity). Это важно для классов, которые используются как значимые объекты или DTO.
@Transient аннотация
@Transient — самая распространённая аннотация для пропуска отдельных полей, но не целого класса.
@Entity
@Table(name = "users")
public class User {
@Id
private Long id;
private String name;
// Это поле не будет персистентным
@Transient
private String tempPassword;
// Это поле тоже не будет сохранено
@Transient
private LocalDateTime cachedTime;
}
@Embeddable для составных значений
Если класс используется как часть сущности (не самостоятельная сущность):
@Embeddable
public class Address {
private String street;
private String city;
private String country;
private String zipCode;
}
@Entity
@Table(name = "users")
public class User {
@Id
private Long id;
private String name;
// Address не является отдельной сущностью, а встраивается
@Embedded
private Address address;
}
Не добавлять @Entity вообще
Самый простой способ игнорировать класс — просто не помечать его аннотацией @Entity:
// Это НЕ сущность (нет @Entity)
public class UserDTO {
private Long id;
private String name;
private String email;
// Этот класс не будет управляться JPA
}
// А вот это сущность
@Entity
@Table(name = "users")
public class User {
@Id
private Long id;
private String name;
private String email;
}
@MappedSuperclass для наследования
Для базовых классов, которые не должны быть сущностями:
// Это не сущность, но его свойства наследуются
@MappedSuperclass
public abstract class BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@CreationTimestamp
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
}
// Это сущность, наследующая поля BaseEntity
@Entity
@Table(name = "users")
public class User extends BaseEntity {
private String name;
private String email;
}
@ElementCollection для коллекций
Для коллекций простых значений, которые не являются отдельными сущностями:
@Entity
@Table(name = "users")
public class User {
@Id
private Long id;
private String name;
// Коллекция простых значений, не сущностей
@ElementCollection
@CollectionTable(name = "user_phone_numbers")
private List<String> phoneNumbers = new ArrayList<>();
}
@Convert для кастомных типов
Если нужно преобразовать сложный объект в простой тип для БД:
// Converter для преобразования объекта в строку
@Converter
public class AddressConverter implements AttributeConverter<Address, String> {
@Override
public String convertToDatabaseColumn(Address address) {
if (address == null) return null;
return address.getStreet() + "," + address.getCity();
}
@Override
public Address convertToEntityAttribute(String dbData) {
if (dbData == null) return null;
String[] parts = dbData.split(",");
Address address = new Address();
address.setStreet(parts[0]);
address.setCity(parts[1]);
return address;
}
}
@Entity
@Table(name = "users")
public class User {
@Id
private Long id;
@Convert(converter = AddressConverter.class)
private Address address;
}
Полная таблица решений
| Подход | Для чего | Как использовать | БД таблица |
|---|---|---|---|
| Нет @Entity | Простые DTO/POJO | Просто класс | НЕТ |
| @Transient | Пропуск одного поля | На поле | Поле пропускается |
| @Embeddable | Встроенный объект | На классе + @Embedded | Той же строки |
| @MappedSuperclass | Базовый класс | На базовом классе | Нет отдельной таблицы |
| @ElementCollection | Коллекция значений | На коллекции | Отдельная таблица |
| @Convert | Кастомное преобразование | На поле/классе | Любой тип |
Практические примеры
Пример 1: DTO без @Entity
// Это НЕ сущность, а простой объект передачи данных
public class UserResponseDTO {
private Long id;
private String name;
private String email;
// Конструктор, getters, setters
public UserResponseDTO(User user) {
this.id = user.getId();
this.name = user.getName();
this.email = user.getEmail();
}
}
// Использование
@Service
public class UserService {
public UserResponseDTO getUserById(Long id) {
User user = userRepository.findById(id).orElseThrow();
return new UserResponseDTO(user); // Преобразование
}
}
Пример 2: Временные поля с @Transient
@Entity
@Table(name = "users")
public class User {
@Id
private Long id;
private String name;
private String email;
// Это поле не будет сохранено в БД
@Transient
private String temporaryToken;
// Кэшируемое значение
@Transient
private LocalDateTime tokenExpiresAt;
// Вычисляемое поле
@Transient
public boolean isTokenExpired() {
return LocalDateTime.now().isAfter(tokenExpiresAt);
}
}
Пример 3: Встроенный объект с @Embeddable
@Embeddable
public class Contact {
private String email;
private String phoneNumber;
}
@Entity
@Table(name = "users")
public class User {
@Id
private Long id;
private String name;
// Contact встраивается в ту же таблицу users
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "email", column = @Column(name = "email")),
@AttributeOverride(name = "phoneNumber", column = @Column(name = "phone"))
})
private Contact contact;
}
Пример 4: Базовый класс с @MappedSuperclass
@MappedSuperclass
public abstract class AuditableEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
@CreationTimestamp
protected LocalDateTime createdAt;
@UpdateTimestamp
protected LocalDateTime updatedAt;
@Column(name = "created_by")
protected String createdBy;
@Column(name = "updated_by")
protected String updatedBy;
}
@Entity
@Table(name = "users")
public class User extends AuditableEntity {
private String name;
private String email;
}
@Entity
@Table(name = "products")
public class Product extends AuditableEntity {
private String title;
private BigDecimal price;
}
Лучшие практики
- Используйте @Transient для временных полей — когда нужны данные только в памяти
- Используйте @Embeddable для объектов значений — для встраивания структур
- Не используйте @Entity для DTO — отделяйте слои
- Используйте @MappedSuperclass для наследования — для переиспользования полей
- Используйте @ElementCollection для простых коллекций — не требует отдельной сущности
Иерархия наследования
Классы для JPA:
├── @Entity → Отдельная таблица
├── @Embeddable → Встроена в таблицу родителя
├── @MappedSuperclass → Свойства наследуются
└── POJO (без аннотаций) → Не управляется JPA
Вывод: Чтобы игнорировать класс как сущность в JPA, есть несколько подходов:
- Просто не добавлять @Entity (для DTO и POJO)
- Использовать @Transient для отдельных полей
- Использовать @Embeddable для встраивания структур
- Использовать @MappedSuperclass для базовых классов Выбор зависит от того, как вы хотите использовать класс и его данные.