001package com.avaje.ebean.annotation; 002 003import java.lang.annotation.ElementType; 004import java.lang.annotation.Retention; 005import java.lang.annotation.RetentionPolicy; 006import java.lang.annotation.Target; 007 008import com.avaje.ebean.Query; 009 010/** 011 * Specify an explicit sql select statement to use for querying an entity bean. 012 * <p> 013 * The reason for using explicit sql is that you want better control over the 014 * exact sql or sql that Ebean does not generate for you (such as group by, 015 * union, intersection, window functions, recursive queries). 016 * </p> 017 * <p> 018 * An example of two sql select queries deployed on the ReportTopic entity bean. 019 * The first one has no name specified so it becomes the default query. The 020 * second query extends the first adding a where clause with a named parameter. 021 * </p> 022 * 023 * <pre class="code"> 024 * ... 025 * @Entity 026 * @Sql(select = { 027 * @SqlSelect(query = 028 * "select t.id, t.title, count(p.id) as score "+ 029 * "from f_topic t "+ 030 * "join f_topic_post p on p.topic_id = t.id "+ 031 * "group by t.id, t.title"), 032 * @SqlSelect( 033 * name = "with.title", 034 * extend = "default", 035 * debug = true, 036 * where = "title like :likeTitle") 037 * }) 038 * public class ReportTopic 039 * @Id Integer id; 040 * String title; 041 * Double score; 042 * ... 043 * </pre> 044 * 045 * <p> 046 * An example using the first "default" query. 047 * </p> 048 * 049 * <pre class="code"> 050 * 051 * List<ReportTopic> list = 052 * Ebean.find(ReportTopic.class) 053 * .having().gt("score", 0) 054 * .findList(); 055 * 056 * </pre> 057 * 058 * <p> 059 * The resulting sql, note the having clause has been added. 060 * </p> 061 * 062 * <pre class="code"> 063 * select t.id, t.title, count(p.id) as score 064 * from f_topic t join f_topic_post p on p.topic_id = t.id 065 * group by t.id, t.title 066 * having count(p.id) > ? 067 * </pre> 068 * 069 * <p> 070 * An example using the second query. Note the named parameter "likeTitle" must 071 * be set. 072 * </p> 073 * 074 * <pre class="code"> 075 * List<ReportTopic> list = 076 * Ebean.find(ReportTopic.class, "with.title") 077 * .set("likeTitle", "a%") 078 * .findList(); 079 * </pre> 080 * 081 * <p> 082 * Ebean tries to parse the sql in the query to determine 4 things 083 * <li>Location for inserting WHERE expressions (if required)</li> 084 * <li>Location for inserting HAVING expressions (if required)</li> 085 * <li>Mapping of columns to bean properties</li> 086 * <li>The order by clause</li> 087 * </p> 088 * <p> 089 * If Ebean is unable to parse out this information (perhaps because the sql 090 * contains multiple select from keywords etc) then you need to manually specify 091 * it. 092 * </p> 093 * <p> 094 * Insert ${where} or ${andWhere} into the location where Ebean can insert any 095 * expressions added to the where clause. Use ${andWhere} if the sql already has 096 * the WHERE keyword and Ebean will instead start with a AND keyword. 097 * </p> 098 * <p> 099 * Insert ${having} or ${andHaving} into the location where Ebean can insert any 100 * expressions added to the having clause. Use ${andHaving} if the sql already 101 * has a HAVING keyword and Ebean will instead start with a AND keyword. 102 * </p> 103 * <p> 104 * Use the columnMapping property if Ebean is unable to determine the columns 105 * and map them to bean properties. 106 * </p> 107 * <p> 108 * Example with ${andWhere} & ${having}. 109 * </p> 110 * 111 * <pre class="code"> 112 * @SqlSelect( 113 * name = "explicit.where", 114 * query = 115 * "select t.id, t.title, count(p.id) as score "+ 116 * "from f_topic t, f_topic_post p "+ 117 * "where p.topic_id = t.id ${andWhere} "+ 118 * "group by t.id, t.title ${having}"), 119 * </pre> 120 */ 121@Target({ ElementType.TYPE }) 122@Retention(RetentionPolicy.RUNTIME) 123@Deprecated 124public @interface SqlSelect { 125 126 /** 127 * The name of the query. If left blank this is assumed to be the default 128 * query for this bean type. 129 * <p> 130 * This will default to "default" and in that case becomes the default query 131 * used for the bean. 132 * </p> 133 */ 134 String name() default "default"; 135 136 /** 137 * The tableAlias used when adding where expressions to the query. 138 */ 139 String tableAlias() default ""; 140 141 /** 142 * The sql select statement. 143 * <p> 144 * If this query <em>extends</em> another then this string is appended to the 145 * parent query string. Often when using <em>extend</em> you will leave the 146 * query part blank and just specify a where and/or having clauses. 147 * </p> 148 * <p> 149 * This sql <em>CAN NOT</em> contain named parameters. You have to put these 150 * in the separate where and/or having sections. 151 * </p> 152 * <p> 153 * Ebean automatically tries to determine the location in the sql string for 154 * putting in additional where or having clauses. If Ebean is unable to 155 * successfully determine this then you have to explicitly specify these 156 * locations by including 157 * <em>${where} or ${andWhere} and ${having} or ${andHaving}</em> in the sql. 158 * </p> 159 * <p> 160 * <b>${where}</b> location of where clause (and will add WHERE ... ) <br/> 161 * Use this when there is no where clause in the sql. If expressions are added 162 * to the where clause Ebean will put them in at this location starting with 163 * the WHERE keyword. 164 * <p> 165 * <p> 166 * <b>${andWhere}</b> <br/> 167 * Use this instead of ${where} if there IS an existing where clause in the 168 * sql. Ebean will add the expressions starting with the AND keyword. 169 * <p> 170 * <b>${having}</b> location of having clause (and will add HAVING... ) <br/> 171 * </p> 172 * <p> 173 * <b>${andHaving}</b> <br/> 174 * Use this instead of ${having} when there IS an existing HAVING clause. 175 * Ebean will add the expressions starting with the AND keyword. 176 * </p> 177 * <p> 178 * You can include one of ${where} OR ${andWhere} but not both. 179 * </p> 180 * <p> 181 * You can include one of ${having} OR ${andHaving} but not both. 182 * </p> 183 */ 184 String query() default ""; 185 186 /** 187 * Specify the name of a sql-select query that this one 'extends'. 188 * <p> 189 * When a query is extended the sql query contents are appended together. The 190 * where and having clauses are NOT appended but overridden. 191 * </p> 192 */ 193 String extend() default ""; 194 195 /** 196 * Specify a where clause typically containing named parameters. 197 * <p> 198 * If a where clause is specified with named parameters then they will need to 199 * be set on the query via {@link Query#setParameter(String, Object)}. 200 * </p> 201 * <p> 202 * In the example below the query specifies a where clause that includes a 203 * named parameter "likeTitle". 204 * </p> 205 * 206 * <pre class="code"> 207 * ... 208 * @Entity 209 * @Sql(select = { 210 * ... 211 * @SqlSelect( 212 * name = "with.title", 213 * extend = "default", 214 * debug = true, 215 * where = "title like :likeTitle") 216 * }) 217 * public class ReportTopic 218 * ... 219 * </pre> 220 * 221 * <p> 222 * Example use of the above named query. 223 * </p> 224 * 225 * <pre class="code"> 226 * 227 * Query<ReportTopic> query0 = Ebean.createQuery(ReportTopic.class, "with.title"); 228 * 229 * query0.set("likeTitle", "Bana%"); 230 * 231 * List<ReportTopic> list0 = query0.findList(); 232 * </pre> 233 * 234 */ 235 String where() default ""; 236 237 /** 238 * Specify a having clause typically containing named parameters. 239 * <p> 240 * If a having clause is specified with named parameters then they will need 241 * to be set on the query via {@link Query#setParameter(String, Object)}. 242 * </p> 243 */ 244 String having() default ""; 245 246 /** 247 * (Optional) Explicitly specify column to property mapping. 248 * <p> 249 * This is required when Ebean is unable to parse the sql. This could occur if 250 * the sql contains multiple select keywords etc. 251 * </p> 252 * <p> 253 * Specify the columns and property names they map to in the format. 254 * </p> 255 * 256 * <pre class="code"> 257 * column1 propertyName1, column2 propertyName2, ... 258 * </pre> 259 * 260 * <p> 261 * Optionally put a AS keyword between the column and property. 262 * </p> 263 * 264 * <pre class="code"> 265 * // the AS keyword is optional 266 * column1 AS propertyName1, column2 propertyName2, ... 267 * </pre> 268 * 269 * <p> 270 * <b>column</b> should contain the table alias if there is one 271 * </p> 272 * <p> 273 * <b>propertyName</b> should match the property name. 274 * </p> 275 * 276 * <p> 277 * Example mapping 5 columns to properties. 278 * </p> 279 * 280 * <pre class="code"> 281 * columnMapping="t.id, t.bug_body description, t.bug_title as title, count(p.id) as scoreValue", 282 * </pre> 283 * 284 * <p> 285 * Without this set Ebean will parse the sql looking for the select clause and 286 * try to map the columns to property names. It is expected that Ebean will 287 * not be able to successfully parse some sql and for those cases you should 288 * specify the column to property mapping explicitly. 289 * </p> 290 * 291 */ 292 String columnMapping() default ""; 293 294 /** 295 * Set this to true to have debug output when Ebean parses the sql-select. 296 */ 297 boolean debug() default false; 298}