001package io.ebean; 002 003import io.ebean.bean.EntityBean; 004 005 006/** 007 * A MappedSuperclass base class that provides convenience methods for inserting, updating and 008 * deleting beans. 009 * <p> 010 * By having your entity beans extend this it provides a 'Active Record' style programming model for 011 * Ebean users. 012 * <p> 013 * Note that there is a ebean-mocker project that enables you to use Mockito or similar 014 * tools to still mock out the underlying 'default EbeanServer' for testing purposes. 015 * <p> 016 * You may choose not use this Model mapped superclass if you don't like the 'Active Record' style 017 * or if you believe it 'pollutes' your entity beans. 018 * <p> 019 * You can use Dependency Injection like Guice or Spring to construct and wire a EbeanServer instance 020 * and have that same instance used with this Model and Finder. The way that works is that when the 021 * DI container creates the EbeanServer instance it can be registered with the Ebean singleton. In this 022 * way the EbeanServer instance can be injected as per normal Guice / Spring dependency injection and 023 * that same instance also used to support the Model and Finder active record style. 024 * <p> 025 * If you choose to use the Model mapped superclass you will probably also chose to additionally add 026 * a {@link Finder} as a public static field to complete the active record pattern and provide a 027 * relatively nice clean way to write queries. 028 * <p> 029 * <h3>Typical common @MappedSuperclass</h3> 030 * <pre>{@code 031 * 032 * // Typically there is a common base model that has some 033 * // common properties like the ones below 034 * 035 * @MappedSuperclass 036 * public class BaseModel extends Model { 037 * 038 * @Id Long id; 039 * 040 * @Version Long version; 041 * 042 * @WhenCreated Timestamp whenCreated; 043 * 044 * @WhenUpdated Timestamp whenUpdated; 045 * 046 * ... 047 * 048 * }</pre> 049 * <p> 050 * <h3>Extend the Model</h3> 051 * <pre>{@code 052 * 053 * // Extend the mappedSuperclass 054 * 055 * @Entity @Table(name="o_account") 056 * public class Customer extends BaseModel { 057 * 058 * String name; 059 * ... 060 * } 061 * 062 * }</pre> 063 * <p> 064 * <h3>Modal: save()</h3> 065 * <pre>{@code 066 * 067 * // Active record style ... save(), delete() etc 068 * Customer customer = new Customer(); 069 * customer.setName("AC234"); 070 * 071 * // save() method inherited from Model 072 * customer.save(); 073 * 074 * }</pre> 075 */ 076public abstract class Model { 077 078 /** 079 * Return the underlying 'default' Database. 080 * <p> 081 * This provides full access to the API such as explicit transaction demarcation etc. 082 * <p> 083 * Example: 084 * <pre>{@code 085 * 086 * try (Transaction transaction = Customer.db().beginTransaction()) { 087 * 088 * // turn off cascade persist for this transaction 089 * transaction.setPersistCascade(false); 090 * 091 * // extra control over jdbc batching for this transaction 092 * transaction.setBatchGetGeneratedKeys(false); 093 * transaction.setBatchMode(true); 094 * transaction.setBatchSize(20); 095 * 096 * Customer customer = new Customer(); 097 * customer.setName("Roberto"); 098 * customer.save(); 099 * 100 * Customer otherCustomer = new Customer(); 101 * otherCustomer.setName("Franko"); 102 * otherCustomer.save(); 103 * 104 * transaction.commit(); 105 * 106 * } 107 * 108 * }</pre> 109 */ 110 public static Database db() { 111 return DB.getDefault(); 112 } 113 114 /** 115 * Return a named Database that is typically different to the default database. 116 * 117 * @param server The name of the Database. If this is null then the default Database is returned. 118 */ 119 public static Database db(String server) { 120 return DB.byName(server); 121 } 122 123 /** 124 * Marks the entity bean as dirty. 125 * <p> 126 * This is used so that when a bean that is otherwise unmodified is updated the version 127 * property is updated. 128 * <p> 129 * An unmodified bean that is saved or updated is normally skipped and this marks the bean as 130 * dirty so that it is not skipped. 131 * <p> 132 * <pre>{@code 133 * 134 * Customer customer = Customer.find.byId(id); 135 * 136 * // mark the bean as dirty so that a save() or update() will 137 * // increment the version property 138 * customer.markAsDirty(); 139 * customer.save(); 140 * 141 * }</pre> 142 * 143 * @see Database#markAsDirty(Object) 144 */ 145 public void markAsDirty() { 146 db().markAsDirty(this); 147 } 148 149 /** 150 * Mark the property as unset or 'not loaded'. 151 * <p> 152 * This would be used to specify a property that we did not wish to include in a stateless update. 153 * </p> 154 * <pre>{@code 155 * 156 * // populate an entity bean from JSON or whatever 157 * User user = ...; 158 * 159 * // mark the email property as 'unset' so that it is not 160 * // included in a 'stateless update' 161 * user.markPropertyUnset("email"); 162 * 163 * user.update(); 164 * 165 * }</pre> 166 * 167 * @param propertyName the name of the property on the bean to be marked as 'unset' 168 */ 169 public void markPropertyUnset(String propertyName) { 170 ((EntityBean) this)._ebean_getIntercept().setPropertyLoaded(propertyName, false); 171 } 172 173 /** 174 * Insert or update this entity depending on its state. 175 * <p> 176 * Ebean will detect if this is a new bean or a previously fetched bean and perform either an 177 * insert or an update based on that. 178 * 179 * @see Database#save(Object) 180 */ 181 public void save() { 182 db().save(this); 183 } 184 185 /** 186 * Flush any batched changes to the database. 187 * <p> 188 * When using JDBC batch flushing occurs automatically at commit() time or when the batch size 189 * is reached. This provides the ability to manually flush the batch. 190 * </p> 191 */ 192 public void flush() { 193 db().flush(); 194 } 195 196 /** 197 * Update this entity. 198 * 199 * @see Database#update(Object) 200 */ 201 public void update() { 202 db().update(this); 203 } 204 205 /** 206 * Insert this entity. 207 * 208 * @see Database#insert(Object) 209 */ 210 public void insert() { 211 db().insert(this); 212 } 213 214 /** 215 * Delete this bean. 216 * <p> 217 * This will return true if the bean was deleted successfully or JDBC batch is being used. 218 * </p> 219 * <p> 220 * If there is no current transaction one will be created and committed for 221 * you automatically. 222 * </p> 223 * <p> 224 * If the Bean does not have a version property (or loaded version property) and 225 * the bean does not exist then this returns false indicating that nothing was 226 * deleted. Note that, if JDBC batch mode is used then this always returns true. 227 * </p> 228 * 229 * @see Database#delete(Object) 230 */ 231 public boolean delete() { 232 return db().delete(this); 233 } 234 235 /** 236 * Delete a bean permanently without soft delete. 237 * <p> 238 * This is used when the bean contains a <code>@SoftDelete</code> property and we 239 * want to perform a hard/permanent delete. 240 * </p> 241 * 242 * @see Database#deletePermanent(Object) 243 */ 244 public boolean deletePermanent() { 245 return db().deletePermanent(this); 246 } 247 248 /** 249 * Perform an update using this entity against the specified server. 250 */ 251 public void update(String server) { 252 db(server).update(this); 253 } 254 255 /** 256 * Perform an insert using this entity against the specified server. 257 */ 258 public void insert(String server) { 259 db(server).insert(this); 260 } 261 262 /** 263 * Perform a delete using this entity against the specified server. 264 */ 265 public boolean delete(String server) { 266 return db(server).delete(this); 267 } 268 269 /** 270 * Refreshes this entity from the database. 271 * 272 * @see Database#refresh(Object) 273 */ 274 public void refresh() { 275 db().refresh(this); 276 } 277 278}