|
Java форум JavaTalks форум программистов
|
|
|
|
| Предыдущая тема :: Следующая тема |
| Автор |
Сообщение |
Z___ZZZ : 13 Новичок
|
Дек 29, 2011 11:55 |
|
|
Во-первых, Здравствуйте!
Во-вторых, я новичок!
В-третьих, проблема!
Есть две сущности Person и Address. Необходимо, чтобы сущность Address была вложенной. У меня в таблице address есть foreighn key -personId, который ссылается на primary key (id) таблицы person. В сущностях прописываю связи OneToOne, однако при добавлении записи Person+Address никоим образом не генерируется personId (т.е. оно нулевое), а так как у меня personId not null hibernate выдает ошибку, что couldn not insert
Код
Person
| Код: |
@Entity
@Table(name = "person")
@NamedQueries({
@NamedQuery(name = "Person.findAll", query = "SELECT p FROM Person p")})
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@NotNull
@Column(name = "id")
private Integer id;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 500)
@Column(name = "firstName")
private String firstName;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 500)
@Column(name = "lastName")
private String lastName;
@Column(name = "dob")
@Temporal(TemporalType.DATE)
private Date dob;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "personId")
private Address address;
public Person() {
}
public Address getAddress() {
return address;
}
............
}
|
Address
| Код: |
@Entity
@Table(name = "address")
@NamedQueries({
@NamedQuery(name = "Address.findAll", query = "SELECT a FROM Address a")})
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@NotNull
@Column(name = "id")
private Integer id;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 255)
@Column(name = "city")
private String city;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 500)
@Column(name = "firstString")
private String firstString;
@Size(max = 500)
@Column(name = "secondString")
private String secondString;
@JoinColumn(name = "personId", referencedColumnName = "id", nullable=false)
@OneToOne(optional = false, cascade= CascadeType.ALL)
private Person personId;
public Person getPersonId() {
return personId;
}
public void setPersonId(Person personId) {
this.personId = personId;
}
........................
}
|
А это я создаю таблицу
| Код: |
CREATE TABLE Address(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
personId INT NOT NULL,
city VARCHAR(255) NOT NULL,
firstString VARCHAR(500) NOT NULL,
secondString VARCHAR(500),
FOREIGN KEY (personId) REFERENCES Person(id)
); |
подскажите что-нибудь. У меня personId должен заполняться автоматически, в него должно записываться значение id из Person. Может я не туда забрел вообще?id
|
|
|
|
 |
Mam(O)n : 61 Новичок
|
Дек 29, 2011 12:25 |
|
|
Ну во-первых, а что, если снять @NotNull с поля id?
Ну и во-вторых, если нужна просто вложенная сущность, то может можно обойтись @Embedded/@Embeddable? |
|
|
|
 |
Z___ZZZ : 13 Новичок
|
Дек 29, 2011 13:00 |
|
|
| Mam(O)n писал(а): |
Ну во-первых, а что, если снять @NotNull с поля id?
Ну и во-вторых, если нужна просто вложенная сущность, то может можно обойтись @Embedded/@Embeddable? |
1.снимать not null нельзя - ибо мой personId - это как бы ссылка на запись в таблице person, т.е. она должна заполняться автоматом.
2. условия такие |
|
|
|
 |
Mam(O)n : 61 Новичок
|
Дек 29, 2011 13:10 |
|
|
Ну тут такая тема, что автоматическое значение оно как бы генерируется в момент записи в таблицу, на уровне СУБД, а валидация бинов происходит раньше передачи данных в СУБД, отсюда и срабатывание @NotNull.
И наверное мне стоит уточнить, что аннотация @NotNull отношения к NOT NULL в СУБД не имеет. Эта аннотация относится к JSR 303 Bean Validation. |
|
|
|
 |
Z___ZZZ : 13 Новичок
|
Дек 29, 2011 14:11 |
|
|
| объявил поле personId так , что оно может принимать нулевые значения. в итоге в БД все personId NULL. |
|
|
|
 |
Z___ZZZ : 13 Новичок
|
Дек 29, 2011 16:58 |
|
|
| Суть такая - надо на форме вводит объект класса Person с дополнительными атрибутами. Доп атрибуты - это объект класса Address. Соответственно, удаляя объект Person - удаляется ссылочный объект Address |
|
|
|
 |
Mam(O)n : 61 Новичок
|
Дек 29, 2011 17:02 |
|
|
Я имел ввиду @NotNull не на personId снять, а на id надо снять. Ну да и ладно, первая проблема я как вижу решилась. Теперь вторую проблему надо исправить, приведя аннотации отношений к следующему виду:
| Код: |
@NotNull
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn (name = "addressId", referencedColumnName = "id")
private Address address; |
| Код: |
@NotNull
@OneToOne (cascade= CascadeType.ALL)
@JoinColumn (name = "personId", referencedColumnName = "id")
private Person person; |
|
|
|
|
 |
Z___ZZZ : 13 Новичок
|
Дек 29, 2011 17:27 |
|
|
| Mam(O)n писал(а): |
Я имел ввиду @NotNull не на personId снять, а на id надо снять. Ну да и ладно, первая проблема я как вижу решилась. Теперь вторую проблему надо исправить, приведя аннотации отношений к следующему виду:
| Код: |
@NotNull
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn (name = "addressId", referencedColumnName = "id")
private Address address; |
| Код: |
@NotNull
@OneToOne (cascade= CascadeType.ALL)
@JoinColumn (name = "personId", referencedColumnName = "id")
private Person person; |
|
ок. допустим так я сделал. какие мои дальнейшие действия.
и еще - в вашем коде мне необходимо еще задавать foreighn key addressId в таблице person который будет ссылаться на Address. это я сделаю, но можно было это опустить как я понимаю. |
|
|
|
 |
Mam(O)n : 61 Новичок
|
Дек 29, 2011 17:49 |
|
|
| Z___ZZZ писал(а): |
ок. допустим так я сделал. какие мои дальнейшие действия.
|
Ну допустим можно использовать эти сущности в CRUD операциях так:
| Код: |
@Stateless
@Path ("person")
public class PersonBean
{
@PersistenceContext (unitName = "example")
private EntityManager entityManager;
@GET
@Path ("{id}")
@Produces (MediaType.APPLICATION_JSON)
public Person get (@PathParam("id") Integer id)
{
return entityManager.find(Person.class, id);
}
@PUT
public void put ( @FormParam("firstName") String firstName,
@FormParam("lastName") String lastName,
@FormParam("city") String city,
@FormParam("firstString") String firstString,
@FormParam("secondString") String secondString)
{
Person person = new Person();
Address address = new Address();
person.setAddress(address);
person.setFirstName(firstName);
person.setLastName(lastName);
address.setCity(city);
address.setFirstString(firstString);
address.setSecondString(secondString);
entityManager.persist(person);
}
@DELETE
@Path ("{id}")
public void delete (@PathParam("id") Integer id)
{
entityManager.remove(entityManager.find(Person.class, id));
}
}
|
| Z___ZZZ писал(а): |
и еще - в вашем коде мне необходимо еще задавать foreighn key addressId в таблице person который будет ссылаться на Address. это я сделаю, но можно было это опустить как я понимаю. |
Совершенно верное замечание. Особого смысла держать обратную ссылку я не вижу смысла в контексте отношений данных сущностей, и поле personId из сущности Address можно изъять.[/code][/quote] |
|
|
|
 |
Z___ZZZ : 13 Новичок
|
Дек 29, 2011 17:57 |
|
|
все понял.
да вот в чем проблема то. у меня контроллер уже реализован, все GRUD реализованы. по сабмиту в бд записывается как Person так и Address. проблема именно в том чтобы эти две таблицы как то были связаны, чтобы удалив запись из Person, удалилась соответствующая ему запись из Address. в этом вся загвоздка(( |
|
|
|
 |
Mam(O)n : 61 Новичок
|
Дек 29, 2011 18:07 |
|
|
Я данную связку сущностей у себя на Glassfish-3.1.1 (ORM - EclipseLink) запустил, и при entityManager.remove(person) у меня также из базы средствами ORM и связная запись address вычищается. Если что, сущности у меня так выглядят:
| Код: |
package com.example.entities;
import javax.persistence.*;
import javax.validation.constraints.*;
import lombok.*;
@Entity
public class Person
{
@Id
@Getter @Setter
@GeneratedValue (strategy = GenerationType.IDENTITY)
private Integer id;
@NotNull
@Getter @Setter
@Size (min = 1, max = 500)
@Column (nullable = false)
private String firstName;
@NotNull
@Getter @Setter
@Size (min = 1, max = 500)
@Column (name = "lastName")
private String lastName;
@Getter @Setter
@Temporal (TemporalType.DATE)
private java.util.Date dob;
@NotNull
@Getter @Setter
@OneToOne(cascade = CascadeType.ALL)
private Address address;
}
|
| Код: |
package com.example.entities;
import javax.persistence.*;
import javax.validation.constraints.*;
import lombok.*;
@Entity
public class Address
{
@Id
@Getter @Setter
@GeneratedValue (strategy = GenerationType.IDENTITY)
private Integer id;
@NotNull
@Getter @Setter
@Size (min = 1, max = 255)
@Column (nullable = false)
private String city;
@NotNull
@Getter @Setter
@Size (min = 1, max = 500)
@Column (nullable = false)
private String firstString;
@Getter @Setter
@Size (max = 500)
private String secondString;
}
|
|
|
|
|
 |
Z___ZZZ : 13 Новичок
|
Дек 30, 2011 10:19 |
|
|
короче ничего не получается. все перепробовал, что тут описали.
снимок БД
может я в DAO классе что нитак сделал?
| Код: |
package com.mycompany.person;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
/**
*
* @author TROFIMOVEA
*/
@Repository
public class AddressDAOImpl implements AddressDAO{
@Autowired
private SessionFactory sessionFactory;
@Override
public void addAddress(Address address) {
sessionFactory.getCurrentSession().save(address);
}
/* @Override
public void deleteAddress(Integer id) {
Address address = (Address) sessionFactory.getCurrentSession().load(
Address.class, id);
if (null != address) {
sessionFactory.getCurrentSession().delete(address);
}*/
} |
|
|
|
|
 |
Mam(O)n : 61 Новичок
|
Дек 30, 2011 11:39 |
|
|
Ну в общем то правильнее будет манипулировать на уровне orm только одной сущностью, например Person, а сущность Address, которая должна быть указана внутри сущности Person, уже по указанному CascadeType.ALL автоматически и сохраняться и удаляться будет вместе с сущностью Person. Вот например, в мной приведённом коде restful сессионного бина создаётся два pojo Person и Address, затем присваивается person.setAddress(address) и делается один entityManger.persist(person), который убивает два зайца - сохраняет сущность и Person и Address. Также и удаление происходит вытягиванием только сущности Person.
И да, SessionFactory, это hibernate-specific и выходит за рамки JPA. Тут я не могу подсказать, может у него и поведение другое. |
|
|
|
 |
sgdread : 2184 JT Библиотекарь Откуда: USA
|
Дек 30, 2011 11:55 |
|
|
| Mam(O)n писал(а): |
| CascadeType.ALL автоматически и сохраняться и удаляться будет вместе с сущностью Person. |
Есть нюансы. К примеру в Hibernate на коллекциях сиротки не удаляются. Нужно ставить свойство orphanRemoval:
| Код: |
| @OneToMany(mappedBy=”foo”, orphanRemoval=true) |
| Mam(O)n писал(а): |
| И да, SessionFactory, это hibernate-specific и выходит за рамки JPA. Тут я не могу подсказать, может у него и поведение другое. |
В JPA вместо SessionFactory используется EntityManager. _________________
 |
|
|
|
 |
Mam(O)n : 61 Новичок
|
Дек 30, 2011 12:22 |
|
|
| sgdread писал(а): |
Есть нюансы. К примеру в Hibernate на коллекциях сиротки не удаляются. Нужно ставить свойство orphanRemoval: |
Ну это какбы не ньюанс, это часть стандарта JPA. Используется это в таком случае:
| Код: |
Person person = new Person();
Address oldAddress = new Address();
person.set(oldAddress);
entityManager.persist(person);
Address newAddress = new Address();
person.set(newAddress);
entityManager.update(person);
// И вот теперь oldAddress "сирота" и будет уничтожен при orphanRemoval=true
|
|
|
|
|
 |
|
|
|