简体   繁体   English

道课的通用课

[英]Generic class for the Dao classes

I am trying setting a generic class which will serve as base class for all my Dao classes in my application, but I am facing an error right now. 我正在尝试设置一个通用类,该通用类将作为我的应用程序中所有Dao类的基类,但是我现在遇到错误。 My generic class is defined this way; 我的通用类是这样定义的;

public class Dao<E> {

    private final E entity;

    @Autowired
    SessionFactory sessionFactory;

    protected Session getCurrentSession(){
        return sessionFactory.getCurrentSession();
    }

    public Dao(E entity) {  
        this.entity = entity;
    }

    public E getEntity() {
        return this.entity;
    }

    @Transactional
    public boolean persist(E transientInstance) {
        try {
            sessionFactory.getCurrentSession().persist(transientInstance);
            return true;
        } catch (RuntimeException re) {
            return false;
        }
    }

    @Transactional
    public boolean remove(E transientInstance) {
        try {
            sessionFactory.getCurrentSession().delete(transientInstance);
            return true;
        } catch (RuntimeException re) {
            return false;
        }
    }

    @SuppressWarnings("unchecked")
    @Transactional
    public E merge(E detachedInstance) {
        try {
            E result = (E) sessionFactory.getCurrentSession().merge(detachedInstance);
            return result;
        } catch (RuntimeException re) {
            return null;
        }
    }

    @Transactional
    public E findById(int id) {
        try {
            E instance = (E) sessionFactory.getCurrentSession().get(E, id);
            return instance;
        } catch (RuntimeException re) {
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    @Transactional
    public E findByUsername(String username) {
        try {
            E instance = (E) sessionFactory.getCurrentSession().createCriteria(E, username).add(Restrictions.like("login", username)).list().get(0);
            return instance;
        } catch (RuntimeException re) {
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    @Transactional
    public List<E> findAll() {
        try {
            List<E> instance = sessionFactory.getCurrentSession().createCriteria(E).list();
            return instance;
        } catch (RuntimeException re) {
            return null;
        }
    }

}

The methods with error are the last three, and is related to the referente to E by get() and createCriteria() in the implementation of them (the error is E cannot be resolved to a variable ). 带有错误的方法是最后三个方法,它们在实现中与get()和createCriteria()对E的引用有关 (错误是E无法解析为变量 )。 Usually, I use something like 'Usuario.class' when I don't use this generic-based approach. 通常,当我不使用这种基于泛型的方法时,我会使用类似“ Usuario.class”的名称。

Anyone knows how to do fix this error in my generic class (if this approach is even possible). 任何人都知道如何在我的通用类中解决此错误(如果可能的话)。

First of, the type parameter E is not equal to an instance of Class . 首先,类型参数E不等于Class的实例。 And second, due to type erasure in Java everything about E is lost at runtime. 其次,由于Java中的类型擦除,关于E的所有内容在运行时都会丢失。 But it seams that entity passed in as a parameter to the constructor is the type token which to use when trying to ask for the class. 但它表明,作为参数传递给构造函数的entity是在尝试查询类时使用的类型标记。 Hence change the methods as follows: 因此,请如下更改方法:

@Transactional
public E findById(int id) {
    try {
        E instance = (E) sessionFactory.getCurrentSession().get(entity.getClass(), id);
        return instance;
    } catch (RuntimeException re) {
        return null;
    }
}

@SuppressWarnings("unchecked")
@Transactional
public E findByUsername(String username) {
    try {
        E instance = (E) sessionFactory.getCurrentSession().createCriteria(entity.getClass(), username).add(Restrictions.like("login", username)).list().get(0);
        return instance;
    } catch (RuntimeException re) {
        return null;
    }
}

@SuppressWarnings("unchecked")
@Transactional
public List<E> findAll() {
    try {
        List<E> instance = sessionFactory.getCurrentSession().createCriteria(entity.getClass()).list();
        return instance;
    } catch (RuntimeException re) {
        return null;
    }
}

or if entity is not your type token, add a parameter Class<E> clazz to the constructor like this: 或者,如果entity不是您的类型令牌,则向构造函数添加参数Class<E> clazz ,如下所示:

private final E entity;
private final Class<E> clazz;

public Dao(E entity, Class<E> clazz) {  
    this.entity = entity;
    this.clazz = clazz;
}

and use clazz instead of entity.getClass() in my suggested methods. 并在建议的方法中使用clazz而不是entity.getClass()

Just adding on to the answer above. 只需添加上面的答案即可。 If you don't want to pass in arguments to your constructor you can do the following: 如果您不想将参数传递给构造函数,则可以执行以下操作:

private Class<T> type;

public Dao(){

    Type t = getClass().getGenericSuperclass();
    ParameterizedType pt = (ParameterizedType) t;
    type = (Class<T>) pt.getActualTypeArguments()[0];
}

and then reference type in your criteria when you are making queries. 然后在进行查询时在条件中引用类型。

Addendum: Remove your @Transactional annotations from your DAO layer, @Transactional belongs in your service layer 附录:从DAO层中删除@Transactional批注,@ @Transactional属于您的服务层

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM