Отображение коллекций Hibernate: действительно хорошее разделение задач?

Я новичок в Hibernate ORM, и я думаю, что вы можете помочь мне лучше понять его. Точнее, я поймал себя на мысли, что очень хорошо реализовано разделение интересов (конечно, это я не могу понять... но, пожалуйста, объясните мне). Поясню: мне кажется, что основная цель hibernate — позволить разработчику работать с классами, забывая об особенностях баз данных. Хорошо! Но давайте разберем этот случай:

У меня есть объект, скажем, UserDetail, который может быть связан с объектом Athority.

@Entity(name="user")
@Table(name="USERS")
public class User implements UserDetails, DomainObject {

private static final long serialVersionUID = 1L;
private long id;
private String username;
private String password;
Collection<Authority> authorities = new ArrayList<Authority>();

public User() {
    super();
}


@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id", unique=true, nullable=false)
public long getId() {
    return id;
}

//various getters & setters

@OneToMany(mappedBy="user")
public Collection<Authority> getAuthorities() {
    return authorities;
}

public void setAuthorities(Collection<Authority> authorities) {
    this.authorities = authorities;
}       
}

вот объект авторитета

@Entity(name="authority")
@Table(name="AUTHORITIES")
public class Authority implements GrantedAuthority, DomainObject{

private long id;
private User user;
private String authority;  //Spring Security demands them to start with "ROLE_"

public Authority() {
    super();
}


@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id", unique=true, nullable=false)
public long getId() {
    return id;
}

public void setId(long id) {
    this.id = id;
}

@ManyToOne
public User getUser() {
    return user;
}

public void setUser(User user) {
    this.user = user;
}

@Column(name="authority", nullable=false)
public String getAuthority() {
    return this.authority;
}

public void setAuthority(String authority) {
    this.authority = authority;
}

}

хорошо, предположим, что у меня есть UserDaoImpl и AuthorityDaoImpl (здесь опущены для краткости). Если я хочу создать новый UserDetails и сохранить его, я должен сделать следующее (это bean-компонент инициализатора, но здесь это не имеет значения):

@Component
public class Initializer {

    @Autowired
    @Qualifier("userDaoImpl")
    private UserDao userDao;
    @Autowired
    @Qualifier("authorityDaoImpl")
    private AuthorityDao authorityDao;

    @PostConstruct
    public void init()
    {
        if(userDao.loadUserByUsername("admin")==null)
        {
            System.out.println("starting initialization.");
            User admin = new User();
            admin.setUsername("admin");
            admin.setPassword("admin");

            Authority authority = new Authority();
            authority.setAuthority("ROLE_ADMIN");
            authority.setUser(admin);

            admin.getAuthorities().add(authority);

            userDao.save(admin);
            authorityDao.save(authority);
            System.out.println("admin user created.");
        }

    }
}

хорошо, я нахожу странным, что я должен явно вызывать AuthorityDao, чтобы сохранить объект авторитета. Если бы разделение ответственности было реализовано правильно, мне просто нужно было бы добавить объект authority в список полномочий admin и оставить только администратора. Если я это сделаю, единственным объектом, который будет сохранен, будет администратор. Вы не думаете так же? Я что-то упускаю?


person MaVVamaldo    schedule 20.10.2012    source источник


Ответы (2)


да. Вам не хватает одной вещи. Просто добавьте cascade = CascadeType.ALL или cascade = CascadeType.PERSIST (выберите подходящее) в сопоставление oneToMany в сопоставлении объектов Admin, как показано ниже. После этого сохранение adimn также сохранит authority.

     @OneToMany(mappedBy="user", cascade = CascadeType.ALL)
     public Collection<Authority> getAuthorities() {
            return authorities;
     }

Дополнительные сведения о cascade типах и настройках см. здесь: Каскад гибернации.

Это необходимо для поддержки различного поведения дочерних сущностей. Скажем, например, ваш авторитет является главной таблицей, т.е. отображением из таблицы, такой как страна, валюта и т. д. Здесь вам не захочется сохранять/удалять валюту, страну вместе с родительским объектом. Будучи общей структурой, она должна поддерживать несколько аспектов требований.

person Yogendra Singh    schedule 20.10.2012
comment
большое спасибо за ответ! Я изучу атрибут каскада, чтобы увидеть, можно ли использовать его в моем приложении. При подходе к обширному фреймворку, такому как спящий режим, документация огромна, и сложно понять общую картину. - person MaVVamaldo; 20.10.2012

На самом деле автоматическое сохранение связанных объектов может быть включено в отображении двумя различными способами:

Чтобы выразить то, что UML называет композицией (т. е. зависимый объект не может существовать независимо от ссылающегося объекта, на него не могут ссылаться другие объекты), вы можете сделать его @Embeddable. Затем Hibernate будет вставлять, обновлять и удалять зависимый объект вместе с (ассоциацией) с его собственным объектом.

Чтобы выразить то, что UML называет агрегацией (т. е. объект, на который ссылаются, имеет собственное удостоверение и независимый жизненный цикл), вы делаете объект, на который делается ссылка, @Entity. Вы можете указать JPA автоматически каскадировать операции сохранения по ассоциации, указав атрибут каскада.

И, конечно же, любые объекты, загруженные контекстом постоянства, обнаружат изменения и автоматически запишут их в базу данных при фиксации транзакции.

person meriton    schedule 20.10.2012