توسط Criteria API میتوان یک کوئری را بصورت داینامیک و بدون استفاده از HQL ایجاد کرد
Criteria ctr = session.createCriteria (Cat.class);
ctr.setMaxResult(50);
List<Cat> cats = ctr.list();
کد بالا معادل select زدن روی جدولی است که در Entity کلاس Cat تعریف شده است و limit آن روی 50 است
در Criteria ما موارد خواسته شده را با متد هایش ارسال میکنیم و آن برای ما کوئری مورد نیاز را میسازد
List<Cat> cats = session.createCriteria (Cat.class)
.add(Restrictions.like("name","Fritz%"))
.add(Restriction.between("weight",minWeight,maxWeight))
.list();
در کد بالا روی کلاس Cat کوئری زده که name آن با Fritz شروع شده باشد و weight آن بین دو عدد باشد
List cats = session.createCriteria(Cat.class)
.add(Restriction.in("name",new String[]{"Fritz","Izi","Pk"}))
.add(Restriction.disjunction()
.add(Restriction.isNull("age"))
.add(Restriction.eq("age",new Integer(0)))
.add(Restriction.eq("age",new Integer(1)))
.add(Restriction.eq("age",new Integer(2)))
)
.list();
با disjunction یک عبارت OR داخل پرانتزی ایجاد شده است و هر چه add در داخل disjunction قرار بگیرد نقش OR را خواهد داشت و برای اینکه بجای OR از AND استفاده کنیم کافی است بجای disjunction از junction استفاده کنیم
میتوان بجای پاس کردن مقدار "age" از property آن استفاده کرد
Property age = Property.forName("age");
sql restriction : گاهی نیاز است که شروط sql را بکار ببریم
List cats = session.createCriteria(Cat.class)
.add(Restriction.sqlRestriction("lower({alias}.name) like lower(?)" , "Fritz%"
, Hibernate.STRING))
.list();
در عبارت بالا alias همیشه به root entity alias اشاره میکند که در اینجا Cat است (در criteria باید از یک entity ساخته شود همان entity که ابتدای ساخت criteria بکار میبریم root entity است)
Order By در Criteria :
List cats = session.createCriteria(Cat.class)
.add( Restrictions.like("name","F%")
.addOrder(Order.asc("name").nullls(NullPrecedence.LAST))
.addOrder(Order.desc("age")))
.setMaxResults(50)
.list();
در عبارت بالا کوئری را بر اساس name صعودی و بردن null ها به انتها و age بصورت نزولی است
join زدن : در criteria بصورت پیش فرض از inner join استفاده میکند
List cats = session.createCriteria(Cat.class)
.add( Restrictions.like("name","F%"))
.createCriteria("kittens")
.add( Restrictions.like("name","F%"))
.list();
در عبارت بالا kittens اشاره به جدولی دارد که با Cat رابطه ای دارد (مثلا ManyToOne) ومیتوان روی آن join زد در شرط دوم که بعد از kittens آمده است شرط روی جدول kittens اعمال میشود
Alias : با متد createAlias میتوان Alias ساخت تا کوئری ها کوتاه تر شوند
تعریف کردن نوع join :
چون در criteria برای روابط بصورت پیش فرض از inner join استفاده میشود میتوان نوع آنرا تغییر داد
List cats = session.createCriteria(Cat.class)
.createAlias("mate","mt",Criteria.LEFT_JOIN,Resctrictions.like("mt.name","good%"))
.addOrder(Order.asc("mt.age"))
.list();
تعریف کردن Fetch type :
List cats = session.createCriteria(Cat.class)
.add(Restrictions.in("name","Fritz%"))
.setFetchMode("mate",FetchMode.EAGER)
.setFetchMode("kittens",FetchMode.EAGER)
.list();
Example Query : در criteria میتوان با استفاده از ابجکت Example و دادن یک نمونه از Entity ، داینامیک بیشتری به کوئری داد :
Cat cat = new Cat();
cat.setName("kittyCat");
cat.setColor(Color.Black);
List cats = session.createCriteria(Cat.class)
.add(Example.create(cat))
.list();
استفاده از Example با محدودیت هایی روبرو است مثلا نمیتوان روی Compose Object ها کوئری زد و یا like زدن روی رشته ها دشوار تر است
**نکته : در Criteria میتوان به root entity یک alias هم داد و اگر ندهیم خودش یک alias بنام entity_ در نظر میگیرد
**نکته : در هایبرنیت Criteria منسوخ شده است و پیشنهاد میدهد از JPA استفاده کنیم البته Criteria در JPA پیشرفته تر و پیچیده تر است و کمی با criteria در hibernate متفاوت است ولی اصول کارشان یکسان است
Projection : با projection میتوان column هایی که میخواهیم در result داشته باشیم را تعیین کنیم
List cats = session.createCriteria(Cat.class)
.setProjection(Projections.projectionList()
.add(Projections.id())
.add(Projections.property("Entity_field_name_1"))
.add(Projections.property("Entity_field_name_2"))
).list();
در جواب لیستی از آرایه بر میگرداند که میتوان صراحتا نوع آنرا هم مشخص کرد و یک DTO ساخت :
List cats = session.createCriteria(Cat.class)
.setProjection(Projections.projectionList()
.add(Projections.id())
.add(Projections.property("Entity_field_name_1"))
.add(Projections.property("Entity_field_name_2"))
)
.setResultTransformer(new ResultTransformer(){
@Override
public Object transformTuple(Object[] objects , String[] strings){
Cat cat = new Cat();
cat.setId((Integer)objects[0]);
cat.setName((String)objects[1]);
...
return cat;
}
@Override
public List transformList(List list){
return list;
} )
.list();
در متد transformList میتوان نحوه ساخت list را هم مشخص کرد و آنرا بر گرداند
** نکته : میتوان از پیاده سازی های پیش فرض جهت setResultTransformer استفاده کرد که سازنده آنها در Criteria.Projection و ... قرار دارند
sub query با criteria : میتوان با criteria کوئری های داخلی هم ایجاد کرد که قبل از کوئری اصلی باید کوئری های داخلی با استفاده از DetachedCriteria ساخته شوند و بعد روی کوئری اصلی استفاده شوند :
DetachedCriteria avgWeightForName = DetachedCriteria.forClass(Cat.class,"cat2")
.setProjection(Property.forName("weight").avg())
.add(Property.forName("cat2.name").eqProperty("cat.name"));
List cats = session.createCriteria(Cat.class,"cat")
.add(Property.forName("weight").gt(avgWeightForName))
.list();