论坛首页 Java版 DAO

又一个DynamicDao

浏览 674 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
时间:2008-05-14

 

模型如下:

@Entity
public class User extends BaseEntry{
	private String name;
	private int age;
	@OneToMany(mappedBy = "user", cascade=CascadeType.ALL)
	private Set<Article> articles = new HashSet<Article>();
        .......
}
 
@Entity
public class Article extends BaseEntry{
private String title;
	private String content;
	@ManyToOne
	private User user;
	….
}

 

 将Dao继承GenericDao如:

public interface UserDao extends GenericDao<User, Integer>{
}
public interface ArticleDao extends GenericDao<Article, Integer>{
}

 

然后在配置文件中增加如下代码:

<bean id="parentDao" class="com.dynamicDao.GenericDaoFactoryBean"
	abstract="true" p:sessionFactory-ref="sessionFactory"/>
		
<bean id="userDao" parent="parentDao"
	p:daoInterface="com.dynamicDao.fixtures.dao.UserDao">
</bean>
<bean id="articleDao" parent="parentDao"
	p:daoInterface="com.dynamicDao.fixtures.dao.ArticleDao">
</bean>

  在Service中注入Dao即可,如:

public UserService{
@Autowired
UserDao userDao;
...
}
 

 基本功能:

GenericDao继承Session接口,另外还继承以下接口:

public interface TypedSession<T, PK extends Serializable> {
	Criteria createCriteria();
	T load(PK pk);
	T load(PK pk, LockMode lockMode);
	T get(PK pk);
	T get(PK pk, LockMode lockMode);
}

对应着Session中需要实体类型的方法,如T load(PK pk)对应着Session#load(Class entityClass, Serializable pk);
 
public interface SimpleCriteria<T> {
	public SimpleCriteria eq(String property, Object value);
	public SimpleCriteria like(String property, Object value);
	public SimpleCriteria gt(String property, Object value);
	public SimpleCriteria order(String property, boolean... asc);
	public SimpleCriteria include(String...associations);
	public SimpleCriteria limit(int limit);
	public SimpleCriteria page(int pageNum, int pageSize);
	public T first();
	public List<T> all();
}
简单地包装了Criteria(还需完善),使用如下:
userDao.eq("name", "tester1").first()
//eager loading
userDao.eq("id", 1).include("articles").first()
 
public interface BaseDao<T, PK extends Serializable>{
	Class getEntityClass();
	Session getSession();
	SessionFactory getSessionFactory();
	Collection<T> findByHsql(String hsql, Object...args); 
	SimpleCriteria createSimpleCriteria();
}
有些简陋,因为GenericDao已经继承Session。

 动态查询:

UserDao加入以下方法即可:

public interface UserDao extends GenericDao<User, Integer>{
	List<User> findByAge(int age, SimpleCriteria sc);
	User findByNameAndAge(Object...args);
}
SimpleCriteria是用来增加一些额外的条件,只要将SimpleCriteria作为最后一个参数即可,也可以不要,如List<User> findByAge(int age)。
目前不支持关联查询,如ArticleDao.findByUserId(int id)

 

 

自定义接口:

  1. 先定义一个接口,如:
    public interface CustomDao {
    	List<Article> articlesAboutPageTest();
    }
    
  2. 然后实现:

    public class CustomDaoImpl implements CustomDao, GenericDaoAware{
    	private GenericDao genericDao;
    	public List<Article> articlesAboutPageTest() {
    		return this.genericDao.eq("title", "pageTest").all();
    	}
    
    	public void setGenericDao(GenericDao genericDao) {
    		this.genericDao = genericDao;
    	}
    }
    注意这里继承了GenericDaoAware,用来注入GenericDao
  3. 在配置文件中增加:

    <bean id="articleDao" parent="parentDao"
    	p:daoInterface="com.dynamicDao.fixtures.dao.ArticleDao">
    	<property name="advices">
    		<list>
    			<bean class="com.dynamicDao.fixtures.dao.CustomDaoImpl"/>
    		</list>
    	</property>
    </bean>
  4. 最后一步就是让你的Dao继承CustomerDao 如:

     
    public interface ArticleDao extends GenericDao<Article, Integer>, CustomDao{ }
     
   
时间:2008-05-14
没看出来dynamic在哪?就是自己实现了一套Criteria,而且GenericDao都继承Session了,等于把Session整个都暴露给调用dao的人了,那还要dao干虾米?直接访问session不就完了,不明白这个dynamic dao的设是什么目的。
   
0 请登录后投票
时间:2008-05-14
Norther 写道
没看出来dynamic在哪?就是自己实现了一套Criteria,而且GenericDao都继承Session了,等于把Session整个都暴露给调用dao的人了,那还要dao干螃蟹?直接访问session不就完了,不明白这个dynamic dao的设是什么目的。


其实直接实现Session只是一种方式(有点模仿ActiveRecord的意思),完全可以实现其他的GenericDao的接口,如SpringSide的EntityDao<T>接口,或者自己写一个通用的接口。

另外刚才实现了主题:模仿Warp Dynamic Finder的Hibernate Dynamic Dao里面的Query 注解功能,使用如下:

public interface ArticleDao extends GenericDao<Article, Integer>{
	@Query("from Article where title = ?")
	Article getFirstArticleAbout(String title);
}

 另外,请看看代码,可能有些东西我没有表达清楚。

多谢回复.

 

   
0 请登录后投票
时间:2008-05-14

实现Query Annotation的主要代码如下:

public class AnnotationQueryInterceptor extends AbstractMethodInterceptor{

	public Object invoke(MethodInvocation mi) throws Throwable {
		Query query = mi.getMethod().getAnnotation(Query.class); 
		if(null != query){
			if(Collection.class.isAssignableFrom(mi.getMethod().getReturnType())){
				return super.genericDao.findByHsql(query.value(), mi.getArguments());
			}
			else{
				return super.genericDao.findFirstByHsql(query.value(), mi.getArguments());
			}
		}
		return mi.proceed();
	}
}
 
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Query {
	String value() default "";
}

 最后在GenericDaoFactoryBean的方法initInternalAdvices() 中加入addAdvice(new AnnotationQueryInterceptor())即可;

	void initInternalAdvices() {
		addAdvice(new SessionInterceptor());
		addAdvice(new SimpleCriteriaInterceptor());
		addAdvice(new TypedSessionInterceptor());
		addAdvice(new DynamicFinderInterceptor());
		addAdvice(new AnnotationQueryInterceptor());
	} 
 

要扩展其他接口,如ActiveRecord中的find_or_create_by等功能也比较简单。

 

   
0 请登录后投票
时间:2008-05-14
呵呵,老大你写的东东,不错。我学习了(刚刚一新手哈!)
不过,要是再写一点注释就更好了!仍有很多东东没懂。不过慢慢研究了!
不过呢,也谢谢了!
   
0 请登录后投票
论坛首页 Java版 DAO

跳转论坛:
JavaEye推荐