Общий DAO с Hibernate и Spring, это лучший способ, чем этот? - PullRequest
3 голосов
/ 15 февраля 2012
public class GenericDao <T, PK extends Serializable> {

    private final Class<T> type;

    @Resource(name = "sessionFactory")
    private SessionFactory sessionFactory;

    public GenericDao(final Class<T> type) {
    this.type = type;
    }

    public PK save(final T o) {
    return (PK) sessionFactory.getCurrentSession().save(o);
    }
// ... get,delete, etc

Бин контекста приложения:

<bean id="fooDao" class="com.mycompany.dao.GenericDao">
        <constructor-arg>
            <value>com.mycompany.Foo</value>
        </constructor-arg>
    </bean>

А в слое обслуживания вызвать так:

@Autowired
private GenericDao<Foo, Integer> fooDao;
...
public doStuffIncludingSave(Foo foo)
fooDao.save(foo);

Ответы [ 5 ]

13 голосов
/ 08 марта 2012

Хорошее место для начала - это Общая статья DAO , вышедшая в 2006 году, но содержащая некоторую полезную информацию.Чтобы обновить общий DAO для Spring, спящий режим и аннотации, это то, что я сделал.Также эта более новая статья также весьма полезна.

Весь идентификатор является универсальным интерфейсом, чтобы убедиться, что класс имеет I getId() и setId(I id)

Создатьуниверсальный интерфейс DAO

public interface GenericDao<T extends Identifier<I>, I extends Serializable> {
    public T find(I id);
    public void delete(T obj);
    public void saveOrUpdate(T obj);
}

Создание реализации GenericDAO

public abstract class GenericDaoImpl<T extends Identifier<I>, I extends Serializable> implements GenericDao<T, I>{

    private Class<T> type;

    @Autowired
    private SessionFactory sessionFactory;
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    protected SessionFactory getSessionFactory() {
        if (sessionFactory == null)
            throw new IllegalStateException("SessionFactory has not been set on DAO before usage");
        return sessionFactory;
    }

    public Class<T> getType() {
        return type;
    }

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

    @Transactional(readOnly = true)
    @Override
    public T find(I id) {
        return (T) getSessionFactory().getCurrentSession().get(getType(), id);
    }

    @Transactional
    @Override
    public void delete(T obj) {
        getSessionFactory().getCurrentSession().delete(obj);
    }

    @Transactional
    @Override
    public void saveOrUpdate(T obj) {
        getSessionFactory().getCurrentSession().saveOrUpdate(obj);
    }
}

Интерфейс DAO объекта:

public interface SomeObjectDao extends GenericDao<SomeObject, Long>{
}

Реализация DAO объекта

@Repository
public class SomeObjectDaoImpl extends GenericDaoImpl<SomeObject, Long> implements SomeObjectDao {

}

теперь в любом классе, который нуждается в этом, например, в классе обслуживания, вы можете получить автопроводку, просто добавив необходимый вам класс объекта dao

@Autowired
private SomeObjectDao someObjectDao;
2 голосов
/ 15 февраля 2012

Я думаю, что ваше решение в порядке, но вам не нужен параметр класса T. Это просто ограничивает вас и не позволяет повторно использовать один и тот же DAO для целых чисел и строк (например).

Метод сохранения вообще не нуждается в этом типе.

Методы типа get() или find() должны получить общий тип сами:

public <T> T findById(Class<T> clazz, Serializable id);

public <T> List<T> listAll( Class<T> clazz );

2 голосов
/ 15 февраля 2012

Лучше, чем писать самому, будет использовать

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

public interface UserDao extends GenericDao<User, Long> {
     User findByLogin(String login);         
}

Если вам интересно, посмотрите документацию.

1 голос
/ 15 февраля 2012

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

@Bean(name="myAsdfDao")
public GenericDao<MyAsdf, MyAsdfId> getMyAsdfDao() {
    return new GenericDao<MyAsdf, MyAsdfId>();
}

, что позволит вам сохранять специфичные для сущности daos, не передавая тип конструктору через XML-конфигурацию. Это будет в аннотированном классе @Configuration, который предоставляет конфигурацию на основе Java для Spring.

0 голосов
/ 15 февраля 2012

Недостаток такого дизайна - что бы вы сделали, чтобы выполнить какие-то нетривиальные действия?А как насчет действий на многих объектах?Когда количество объектов, используемых в запросе, достигнет некоторого значительного количества (скажем, 1000), вы столкнетесь с большим замедлением из-за нескольких запросов в БД.

Из моего опыта хороший способ создать некоторый класс, подобный представленному GenericDaoи затем извлекать конкретные DAO из него.Это позволяет поместить некоторые полезные общие методы в GenericDao и реализовать конкретные методы в определенных производных.

...