2012-05-26 3 views
3

У меня есть два объекта, родитель и ребенок. Ребенок имеет внешний ключ обратно в поле PARENT_ID в таблице PARENT (база данных MySQL).Как заполнять значения внешнего ключа в конфигурации Hibernate + Spring JPA, когда родительские/дочерние объекты сохраняются одновременно?

Когда объект родительского и дочернего объектов создается и монтируется одновременно, а вызов сохраняется, внешний ключ дочернего PARENT_ID не заполняется автоматически.

Пример код:

@Entity 
@Table(name = "PARENT") 
public class Parent { 
    @Column(name = "PARENT_ID") 
    private Long parentId; 

    @OneToMany(mappedBy = "parent") 
    private List<Child> children; 
} 

@Entity 
@Table(name = "CHILD") 
public class Child { 
    @Column(name = "CHILD_ID") 
    private Long childId; 

    @Column(name = "PARENT_ID") 
    private Long parentId; 

    @ManyToOne 
    @JoinColumn(name = "parent_id") 
    private Parent parent; 
} 

У меня есть два образца для настойчивости:

1) с использованием Hibernate EntityManager:

@PersistenceContext 
EntityManager em; 

... 

em.persist(parent); 

2) Использование экземпляра Spring Data JPA JpaRepository:

public interface ParentRepository extends JpaRepository<Parent, Long> { 

} 

И в моих ParentServiceImpl:

@Autowired 
private ParentRepository parentRepository; 

... 

public Parent save(Parent parent) { 
    return parentRepository.save(parent); 
} 

Какова рекомендуемая стратегия идти о наполнении внешнего ключа? Должен ли объект родительский быть сохранен первым, а затем внешний ключ дочернего объекта, установленный в этой точке? Или есть способ сохранить все это сразу, когда внешний ключ устанавливается автоматически или по ссылке?

Редактировать: Добавлены образцы сохранения.

Редактировать 2 (исправлено!): Проблема решена согласно второму пункту Райана Стюарта. Я удалил поле Long parentId из объекта Child и поместил ссылку @Column для parentId на получателе. Также убедитесь, что правильно настроены ссылки (важно, чтобы Child возвращался к Parent).

+0

Показать код, который используется для сохранения обоих. –

+0

Сделано! В обоих примерах я делаю только один вызов persist. Каскады все работают для обновлений и вставок, где предварительно установлен родительский внешний ключ (сначала сохранен родительский элемент). – skel625

+0

Покажите нам полный код.Как вы создаете родителя и ребенка. Как вы их связываете? Вы говорите о каскадах, но в коде вы не указали. Если вы хотите, чтобы мы объяснили, как ваш код должен быть исправлен, отправьте код, который вы используете. –

ответ

4

Этот код имеет две вещи, предотвращающие его от работы:

  1. Ваши юридические лица не имеют @Id. Вы, вероятно, просто отказались от этого, потому что это пример, но стоит отметить.
  2. Вы дважды скопировали столбец parent_id. У ребенка есть как длинное поле, так и поле родителя, сопоставленное с тем же столбцом. Избавьтесь от Длинного. Это отношения родителей, за которыми вы после.

После этого у вас есть полностью традиционный двунаправленный «один ко многим» со столбцом объединения. Если это не работает для вас, то вы делаете что-то не так в коде, где вы создаете и сохраняете их. Скорее всего, вы не создаете объекты должным образом. Правильный код, использующий эти объекты будут выглядеть примерно так:

Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 
Parent p = new Parent(); 
Child child = new Child(); 
child.parent = p; 
Child child1 = new Child(); 
child1.parent = p; 
p.children = Arrays.asList(child, child1); 
session.save(p); 
session.save(p.children.get(0)); 
session.save(p.children.get(1)); 
tx.commit(); 

Примечание особенно о том, что ребенок должен быть установлен в родительском, а также родителя у ребенка. Не создавайте полуразрушенную объектную модель и ожидайте, что Hibernate очистит ваш беспорядок. Многие люди игнорируют это кажущееся очевидным требование и задаются вопросом, почему Hibernate кажется неустойчивым и/или ненадежным.

+0

Вы были правы в пункте № 1, я исключил их, поскольку я пытался упростить вещи (возможно, слишком много). Ваша точка № 2 сделала трюк! Благодаря! Есть ли причина, по которой вы явно сохраняете дочерние записи в вашем примере? В сложной области это казалось бы довольно громоздким (у меня около 20 объектов, сходящихся с моего основного объекта в разных отношениях). Я вообще не сохраняю никаких дочерних записей, и теперь все отлично работает (вставляет и обновляет все, что работает красиво) !! – skel625

+1

@ skel625: я сохранил все явно, потому что сущности, которые вы отправили, не настроены каскадом, а каскадирование отключено по умолчанию, то есть дети не будут сохранены, если вы не сделаете это самостоятельно. Разумеется, при сохранении каскадов нет никаких оснований. –

+0

Ahhhhh да, что имеет смысл! Спасибо за помощь, очень ценим! – skel625