使用hibernate / DAO问题

时间:2010-04-07 11:38:02

标签: java hibernate dao

大家好,这是我的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个字符长字符串和唯一/主键,以及字段,如地址,dob等(数据库表中共有15列)。现在,在我的测试类中,我将用户添加了类似的值:

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

所以我为所有15个字段做了,而不是在将数据分配给在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); 

我想用这个密钥删除用户,但它明显不同,有人可以解释一下如何做这些。谢谢

更新:

我是否需要将User对象上的所有15个字段设置为删除它,就像我使用save方法一样?

6 个答案:

答案 0 :(得分:2)

现在还没有看过Hibernate很长一段时间,我只能猜测这个问题。

您似乎正在创建User对象,但只填充User ID字段,因此持久层对实际用户一无所知。

我建议使用可以找到具有给定ID的User的检索功能,然后将该User传递给delete方法。

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

这应该可行,因为持久层将了解用户,因此它具有执行删除所需的所有详细信息。

但是,更有效的方法是找到一种按ID删除用户的方法,这样您就不必查询数据库来获取用户的实例,然后将其删除。

希望这会有所帮助。

克里斯

答案 1 :(得分:1)

在理想的世界中,您将模型的业务密钥作为数据库主键,您将不会遇到此问题。但事实并非如此,不是吗?

对于您的特定问题如果非常确定,那么userID将是唯一的,那么您可以尝试这个(取自here):

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();

但是让我警告你。这种代码根本不好。例如,如果您将来确定您在删除中使用的列不再是唯一的,会发生什么?然后你会遇到一个非常严重的错误或一个非常糟糕的重构案例。无论哪种方式,傻瓜式(可能不是有效的和可能不可行的)方式是基于其主键删除记录。

答案 2 :(得分:1)

结帐the documentation。习惯于持久,瞬态和分离实例的概念。要删除实例,请调用

session.delete(persistentInstance)

并更新(尽管您可能不需要使用它),请致电

persistentInstance = session.merge(detachedInstance)

不应该使用更新吗?不,因为您只需要先加载/查找对象,然后再修改它。您对持久对象所做的任何修改都将自动保存回数据库。

答案 3 :(得分:0)

为了删除其ID为“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");

希望这有帮助。

答案 4 :(得分:0)

Hibernate是一个对象关系映射器,也就是说,它在关系数据库世界和面向对象的Java代码之间进行转换。由于主键是数据库概念,因此将它们转换为面向对象的术语(在本例中为对象标识)是hibernate的工作。

也就是说,如果你将主键传递给hibernate,你就不会按预期使用hibernate;调用代码应该表示具有映射对象的持久数据,而不是主键。这也允许hibernate通过检查版本号来自动防止丢失更新。

因此,典型的模式是具有以下特征:

interface UserDAO {
    void delete(User user);
}

并要求DAO调用者提出一个持久对象来传递给它。调用者可能有一个对象位于当前或之前(现在关闭)的会话中,毕竟,他确实以某种方式了解其主键。如果所有其他方法都失败了,您可以使用session.load(User.class, id)向hibernate请求代理传递给delete方法。 (请注意,如果数据库中可能不再存在该对象,则不应使用session.load。)

答案 5 :(得分:0)

在删除之前不需要获取整个实体,既不为删除创建硬编码查询,也不在实体中设置每个字段。

也许更好的方法是为id设置entity并使用Hibernate API本身。

如果某个特定dao用于实体User,如上所述,请尝试:

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);
    }
}