2015-01-13 6 views
5

У меня есть 2 класса: водитель и автомобиль. Таблица автомобилей обновляется в отдельном процессе. Мне нужно иметь свойство в драйвере, что позволяет мне читать полное описание автомобиля и писать только Id, указывающий на существующий автомобиль. Вот пример:JPA отношение много-к-одному - необходимо сохранить только Id

@Entity(name = "DRIVER") 
public class Driver { 
... ID and other properties for Driver goes here ..... 

    @ManyToOne(fetch=FetchType.LAZY) 
    @JoinColumn(name = "CAR_ID") 
    private Car car; 

    @JsonView({Views.Full.class}) 
    public Car getCar() { 
     return car; 
    } 
    @JsonView({Views.Short.class}) 
    public long getCarId() { 
     return car.getId(); 
    } 
    public void setCarId(long carId) { 
     this.car = new Car (carId); 
    } 

} 

Автомобильный объект является типичным объектом JPA без обратной ссылки на драйвер.

Так что я пытаюсь достичь, это: 1) Я могу прочитать полное описание автомобилей, используя подробные JSON View 2) или я могу читать только Id автомобиля в коротких JsonView 3) и самое главное, при создании нового драйвера я просто хочу передать идентификатор JSON автомобиля. Таким образом, мне не нужно делать unnesessery чтение для автомобиля во время сохранения, но просто обновить Id.

Im получать следующее сообщение об ошибке: «объект ссылается на несохраненный переходный экземпляре - сохранить переходный экземпляр перед промывкой: com.Driver.car -> com.Car»

Я не хотят, чтобы обновить экземпляр автомобиля в БДЕ а скорее просто ссылку на него от Driver. Любая идея, как достичь того, чего я хочу?

спасибо.

ОБНОВЛЕНИЕ: Забыл отметить, что идентификатор автомобиля, который я прохожу во время создания Драйвера, является действительным идентификатором существующего автомобиля в БД.

ответ

1

Это сообщение об ошибке означает, что у вас есть временный экземпляр в графе объектов, который явно не сохраняется. Краткое повторение статусов объекта может быть в JPA:

  • Transient: (. И, таким образом, неизвестно, к EntityManager) Новый объект, который еще не был сохранен в базе данных Не имеет набор ID ,
  • Управляемый: Объект, который отслеживает сущ. Управляемые объекты - это то, с чем вы работаете в рамках транзакции, и все изменения, сделанные для управляемого объекта, будут автоматически сохранены после совершения транзакции.
  • Отдельно: Ранее управляемый объект, который по-прежнему доступен после совершения трансмиссии. (Управляемый объект за пределами транзакции.) Имеет идентификатор.

Что сообщение об ошибке сообщает вам, что находящийся (управляемый/отсоединенный) Драйвер-объект, с которым вы работаете, содержит ссылку на объект Car, который неизвестен Hibernate (он временный). Чтобы заставить Hibernate понять, что любые несохраненные экземпляры Car, на которые ссылаются драйвер, который должен быть сохранен, также должны быть сохранены, вы можете вызвать persist-метод EntityManager.

В качестве альтернативы вы можете добавить каскад настойчивый (я думаю, только с верхней части головы, не проверял его), который будет выполнять упор на автомобиль до того, как он будет продолжать работу с драйвером.

@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST) 
@JoinColumn(name = "CAR_ID") 
private Car car; 

При использовании слияния-метод EntityManager для хранения драйвера, вы должны добавить CascadeType.MERGE вместо этого, или оба:

@ManyToOne(fetch=FetchType.LAZY, cascade={ CascadeType.PERSIST, CascadeType.MERGE }) 
@JoinColumn(name = "CAR_ID") 
private Car car; 
+0

Спасибо Тобб. Так что, если Im создает драйвер из следующего Json {"name": "Joe Doe", "carId": 123}, где автомобиль с идентификатором 123 уже существует, то объект существует в БД. Означает ли это, что я не могу обновить Dirver :: carId, если я не обновляю ссылку на Car также? –

+1

Первое, что связано с JPA, заключается в том, что вам нужно перестать думать в терминах базы данных. JPA имеет дело с объектами Java, это то, что вы запрашиваете, и это то, что вы получаете. У водителя нет атрибута carId, у него есть атрибут Car. Итак, если вы получите эти данные (я думаю, что имя - это имя нового драйвера), сначала вы должны найти EntityManager # find на carId, чтобы получить Car-объект. Затем создайте новый драйвер, присвойте ему загруженный автомобиль и отправьте его в EntityManager # persist. Поскольку автомобиль уже сохраняется и управляется, я не думаю, что вам нужен какой-нибудь каскад, чтобы это сработало. – Tobb

+0

Я вижу. Думаю, для меня нет способа создать объект Car, как и я, и отметить его как сохраненный (подавая его только Id). Похоже на неудобное ограничение для тех, кто приходит из чистого мира запросов БД, где обновление столбца идентификатора - простая задача. Я предполагаю, что другим решением было бы изменить поле CAR_ID от @ManyToOne до базового длинного поля и добавить Transient field Car. Это позволит мне работать только с идентификаторами во время получения и установки, и когда мне нужно будет получить подробную информацию о машине, я могу установить поле «Автомобиль» у контроллера Resuorce, прочитав этот автомобиль явно. Цените свою помощь. –

-1

Использование каскада в ManyToOne аннотации @ManyToOne (каскад = CascadeType.Remove)

3
public void setCarId(long carId) { 
     this.car = new Car (carId); 
    } 

Это на самом деле не сохраняется версия car. Так что это переходный объект, потому что он не id. JPA требует, чтобы вы заботились об отношениях. Если объект является новым (не управляется контекстом), он должен быть сохранен, прежде чем он сможет связываться с другими управляемыми/удаленными объектами (фактически объект MASTER может поддерживать его дочерние элементы с помощью каскадов).

Два способа: каскады или сохранить & поиска из БД.

Также вы должны избегать установки объекта IDот руки. Если вы не хотите обновлять/перенести автомобиль его объектом MASTER, вы должны получить CAR из базы данных и сохранить свой драйвер с его экземпляр. Итак, если вы это сделаете, Car будет отделен от контекста постоянства, НО все же он будет иметь и ID и может быть связан с любым Entity без аффектов.

+0

Спасибо Энтузиаст. Означает ли это, что его переходный процесс, потому что Id не существует или я его инициализировал каким-то образом, читая? Идентификатор причины автомобиля, что передача Im действительна –

+0

Да, это потому, что он не зарегистрирован в контексте сохранения. JPA не может видеть это как сохраненный объект вообще! :) Даже он не существует в БД, так как вы можете связать его с чем-то, кто не существует? :) – 00Enthusiast

8

Вы можете сделать это с помощью getReference вызова в EntityManager:

EntityManager em = ...; 
Car car = em.getReference(Car.class, carId); 

Driver driver = ...; 
driver.setCar(car); 
em.persist(driver); 

Это не приведет к выполнению инструкции SELECT из базы данных.

3

Вы можете работать только с car ID, как это:

@JoinColumn(name = "car") 
@ManyToOne(targetEntity = Car.class, fetch = FetchType.LAZY) 
@NotNull(message = "Car not set") 
@JsonIgnore 
private Car car; 

@Column(name = "car", insertable = false, updatable = false) 
private Long carId; 
+1

Установив insertable = false, updatable = false для объекта, а не идентификатора, мне удалось вставить дочерний элемент с допустимым родительским идентификатором без необходимости извлечения родителя. Спасибо за совет! –