← Назад к вопросам

Какую бы аннотацию использовал, чтобы игнорировать класс как сущность?

1.0 Junior🔥 151 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Аннотации для игнорирования класса как сущности в 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;
}

Лучшие практики

  1. Используйте @Transient для временных полей — когда нужны данные только в памяти
  2. Используйте @Embeddable для объектов значений — для встраивания структур
  3. Не используйте @Entity для DTO — отделяйте слои
  4. Используйте @MappedSuperclass для наследования — для переиспользования полей
  5. Используйте @ElementCollection для простых коллекций — не требует отдельной сущности

Иерархия наследования

Классы для JPA:
├── @Entity → Отдельная таблица
├── @Embeddable → Встроена в таблицу родителя
├── @MappedSuperclass → Свойства наследуются
└── POJO (без аннотаций) → Не управляется JPA

Вывод: Чтобы игнорировать класс как сущность в JPA, есть несколько подходов:

  • Просто не добавлять @Entity (для DTO и POJO)
  • Использовать @Transient для отдельных полей
  • Использовать @Embeddable для встраивания структур
  • Использовать @MappedSuperclass для базовых классов Выбор зависит от того, как вы хотите использовать класс и его данные.
Какую бы аннотацию использовал, чтобы игнорировать класс как сущность? | PrepBro