Работа с проблемами гибернации / DAO - PullRequest
1 голос
/ 07 апреля 2010

Привет всем, вот мой класс DAO:

public class UsersDAO extends HibernateDaoSupport {

    private static final Log log = LogFactory.getLog(UsersDAO.class);

    protected void initDao() {
        //do nothing
    }

    public void save(User transientInstance) {
        log.debug("saving Users instance");
        try {
            getHibernateTemplate().saveOrUpdate(transientInstance);
            log.debug("save successful");
        } catch (RuntimeException re) {
            log.error("save failed", re);
            throw re;
        }
    }

public void update(User transientInstance) {
        log.debug("updating User instance");
        try {
            getHibernateTemplate().update(transientInstance);
            log.debug("update successful");
        } catch (RuntimeException re) {
            log.error("update failed", re);
            throw re;
        }
    }

    public void delete(User persistentInstance) {
        log.debug("deleting Users instance");
        try {
            getHibernateTemplate().delete(persistentInstance);
            log.debug("delete successful");
        } catch (RuntimeException re) {
            log.error("delete failed", re);
            throw re;
        }
    }

    public User findById( java.lang.Integer id) {
        log.debug("getting Users instance with id: " + id);
        try {
            User instance = (User) getHibernateTemplate()
                    .get("project.hibernate.Users", id);
            return instance;
        } catch (RuntimeException re) {
            log.error("get failed", re);
            throw re;
        }
    }

}

Теперь я написал тестовый класс (не тест junit), чтобы проверить, все ли работает, у моего пользователя есть следующие поля в базе данных: userID, длина которого 5 символов, уникальный / первичный ключ, а также такие поля, как address, dob и т. Д. (всего 15 столбцов в таблице базы данных). Теперь в моем тестовом классе я заинтригован, Пользователь добавил значения как:

User user = new User;
user.setAddress("some address");

и так я сделал для всех 15 полей, чем в конце назначения данных для объекта User, который я вызвал в DAO, чтобы сохранить их в базе данных UsersDao.save(user); и сохранить, работает просто отлично. Мой вопрос: как обновить / удалить пользователей, используя ту же логику?

Пример Fox, я попытался (чтобы удалить пользователя из таблицы пользователей):

User user = new User;
user.setUserID("1s54f"); // which is unique key for users no two keys are the same
UsersDao.delete(user); 

Я хотел удалить пользователя с этим ключом, но он явно другой, может кто-нибудь объяснить, пожалуйста, как это сделать. спасибо

ОБНОВЛЕНИЕ:

Нужно ли мне устанавливать все 15 полей в объекте User, чтобы удалить его, как я это сделал с методом сохранения?

Ответы [ 6 ]

2 голосов
/ 07 апреля 2010

Не смотря на Hibernate долгое время, я могу только рискнуть предположить проблему.

Похоже, что вы создаете объект User, но заполняете только поле User ID, поэтому слой постоянства ничего не знает о реальном пользователе.

Я бы порекомендовал использовать функцию получения, которая может найти пользователя с заданным идентификатором, а затем передать этого пользователя в метод удаления.

User u = UsersDao.findById("1s54f");
UsersDao.delete(u);

Это должно работать, так как слой постоянства будет знать о пользователе, поэтому он имеет все детали, необходимые для удаления.

Однако более эффективным способом было бы найти способ удаления пользователя по идентификатору, поэтому вам не нужно запрашивать базу данных, чтобы получить экземпляр пользователя, а затем удалить его.

Надеюсь, это поможет.

Chris

1 голос
/ 07 апреля 2010

Оформить документацию . Привыкайте к концепции постоянных, временных и отдельных экземпляров. Чтобы удалить экземпляр, вы звоните

session.delete(persistentInstance)

и для обновления (хотя вам, вероятно, не нужно его использовать), позвоните

persistentInstance = session.merge(detachedInstance)

Не нужно ли использовать обновление? Нет, потому что вам просто нужно сначала загрузить / найти объект, а затем изменить его. Любые изменения, внесенные в постоянный объект, будут автоматически сохранены обратно в базу данных.

1 голос
/ 07 апреля 2010

В идеальном мире у вас будет бизнес-ключ вашей модели в качестве первичного ключа базы данных, и у вас не будет этой проблемы. Но это не так, не правда ли?

Для вашей конкретной проблемы если вы очень уверены , что userID будет уникальным, то вы можете попробовать это (взято из здесь ):

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

String hqlDelete = "delete User u where u.userID = :id";

int deletedEntities = s.createQuery( hqlDelete )
        .setString( "id", userID )
        .executeUpdate();
tx.commit();
session.close();

Но позвольте мне предупредить вас. Этот код не очень хорош. Например, что произойдет, если в будущем вы решите, что столбец, который вы использовали при удалении, больше не является уникальным? Тогда вы столкнетесь с очень серьезной ошибкой или очень плохим случаем рефакторинга. В любом случае надежный (может быть неэффективный и нереальный) способ заключается в удалении записей на основе их первичного ключа.

0 голосов
/ 27 сентября 2014

Нет необходимости извлекать целую сущность перед ее удалением, ни создавать жестко закодированный запрос на удаление, ни устанавливать каждое поле в сущности.

Возможно, лучший способ сделать это - установить id для entity и используйте сам Hibernate API.

Если для сущности User используется определенный dao, как описано в вопросе, попробуйте:

public void remove(Serializable id) throws InstantiationException, IllegalAccessException {
    User user = new User();
    getSessionFactory().getClassMetadata(getEntityClass()).setIdentifier(user, id, (SessionImplementor) getSessionFactory().getCurrentSession());
    getHibernateTemplate().delete(entity);
}

Как видно, ни ненужныхвыполняется операция в базе данных.

И это можно использовать в общем виде, если GenericDao реализован так:

public void remove(Serializable id) throws InstantiationException, IllegalAccessException {
    Model entity = entityClass.newInstance();
    getSessionFactory().getClassMetadata(getEntityClass()).setIdentifier(entity, id, (SessionImplementor) getSessionFactory().getCurrentSession());
    getHibernateTemplate().delete(entity);
}

В обоих случаях Dao необходимо расширить org.springframework.orm.hibernate4.support.HibernateDaoSupport, чтобы получитьПреимущества.

Вот фрагмент общего:

public class GenericDaoImpl<Model> extends HibernateDaoSupport implements GenericDao<Model> {

   private Class<Model> entityClass;

   public GenericDaoImpl() {
       this.entityClass = (Class<Model>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    /* CRUD are implemented here  */


    public void remove(Serializable id) throws InstantiationException, IllegalAccessException {
        Model entity = entityClass.newInstance();
        getSessionFactory().getClassMetadata(getEntityClass()).setIdentifier(entity, id, (SessionImplementor) getSessionFactory().getCurrentSession());
        getHibernateTemplate().delete(entity);
    }
}
0 голосов
/ 07 апреля 2010

Hibernate - это объектно-реляционный картограф, то есть он транслирует между миром реляционных баз данных и объектно-ориентированным Java-кодом. Поскольку первичные ключи являются концепцией базы данных, задача Hibernate - перевести их в объектно-ориентированные термины (в данном случае: идентификатор объекта).

То есть, если вы передаете первичные ключи в спящий режим, вы не используете спящий режим, как предполагалось; вызывающий код должен представлять постоянные данные с сопоставленными объектами, а не первичными ключами. Это также позволяет hibernate автоматически защищаться от потерянных обновлений, проверяя номера версий.

Типичный шаблон поэтому должен иметь следующую подпись:

interface UserDAO {
    void delete(User user);
}

и требует, чтобы вызывающий объект DAO придумал постоянный объект для передачи ему. У вызывающего может быть такой объект, лежащий около текущего или предыдущего (теперь закрытого) сеанса, в конце концов, он каким-то образом узнал о его первичном ключе. Если ничего не помогает, вы можете использовать session.load(User.class, id), чтобы запросить у hibernate прокси для передачи методу удаления. (Обратите внимание, что не следует использовать session.load, если объект больше не существует в базе данных.)

0 голосов
/ 07 апреля 2010

Чтобы удалить пользователя с его идентификатором "1s54f", вы должны создать HQL удаления следующим образом:

public void delete(String id) {
        log.debug("deleting Users instance");
        try {
            final String deleteQuery = "delete from User where id = :id";
            final Query query = getSession().createQuery(deleteQuery);
            final query.setString("id",id);
            final int rowCount = query.executeUpdate(); // check that the rowCount is 1
            log.debug("delete successful");
        } catch (RuntimeException re) {
            log.error("delete failed", re);
            throw re;
        }
 }

Затем вы можете использовать этот метод, например:

userDao.delete("1s54f");

Надеюсь, это поможет.

...