private SqlStatement GetRetrieveStatement(Type type, Key key) { SqlStatement stmt = null; // check whether we can use cached statement (key must be for primary key) if (IsPrimaryKeyForType(type, key)) { // select is by primary key - expect exactly one row and complain if not found stmt = GetStatement(type, key, StatementType.Select); stmt.SetParameters(key, true); } else { stmt = GetRetrieveListStatement(type, key); } Check.VerifyNotNull(stmt, "Unable to create query for type {0} using key {1}", type.Name, key.ToString()); return(stmt); }
/// <summary> /// Internal helper method used for standard CRUD operations on known types. /// </summary> /// <param name="obj">The object instance being operated on</param> /// <param name="st">The statement type</param> /// <param name="conn">An existing database connection to reuse. This is useful /// when you need to execute statements in the same session as a previous statement.</param> /// <param name="tr">The database transaction for when participating in transactions.</param> /// <returns>The result of the operation</returns> internal SqlResult Execute(object obj, StatementType st, IDbConnection conn, IDbTransaction tr) { ObjectMap map = ObjectFactory.GetMap(this, obj); // perform validations first if (StatementType.Insert == st || StatementType.Update == st) { ValidationBroker.Validate(obj); } if (map.IsSoftDelete && st == StatementType.Delete) { st = StatementType.SoftDelete; } SqlStatement stmt = GetStatement(obj, st); stmt.SetParameters(obj, true); // connections are supplied from outside when in a transaction or executing batch queries conn = tr != null ? tr.Connection : conn ?? stmt.SessionBroker.Provider.GetConnection(); SqlResult sr = stmt.Execute(conn, tr); // throw an error if execution failed Check.Verify(sr.ErrorCode == 0, Error.StatementError, sr.Error, stmt.Sql); // check that statement affected a row if (st == StatementType.Insert || st == StatementType.Update || st == StatementType.Delete || st == StatementType.SoftDelete) { Check.Verify(sr.RowsAffected >= 1, Error.UnexpectedRowCount, sr.RowsAffected, "1+"); } // update identity values for inserts if (st == StatementType.Insert) { if (sr.LastRowId != 0 && map.IdentityMap != null) { map.SetIdentity(obj, sr.LastRowId); } if (obj is IEntity) { (obj as IEntity).IsPersisted = true; } // this is not really necessary but nice for error checking (also used in test cases) if (map.InheritanceMap != null) { map.InheritanceMap.SetValue(obj, obj.GetType().AssemblyQualifiedName); } } // update/invalidate the cache if (GentleSettings.CacheObjects && map.CacheStrategy != CacheStrategy.Never) { if (st == StatementType.Insert) { // insert new object into cache CacheManager.Insert(map.GetInstanceHashKey(obj), obj, map.CacheStrategy); // invalidate query results for select statements for this type, reducing the // effectiveness of the cache (but ensuring correct results) if (GentleSettings.CacheStatements) { CacheManager.ClearQueryResultsByType(map.Type); } } else if (st == StatementType.Delete || st == StatementType.SoftDelete) { // remove invalidated object from the cache CacheManager.Remove(obj); // invalidate query results for select statements for this type, reducing the // effectiveness of the cache (but ensuring correct results) if (GentleSettings.CacheStatements) { CacheManager.ClearQueryResultsByType(map.Type); } } } // update the in-memory version/revision counter for objects under concurrency control if (st == StatementType.Update && GentleSettings.ConcurrencyControl) { if (map.ConcurrencyMap != null) { FieldMap fm = map.ConcurrencyMap; long version = Convert.ToInt64(fm.GetValue(obj)); // handle wrap-around of the version counter if ((fm.Type.Equals(typeof(int)) && version == int.MaxValue) || (fm.Type.Equals(typeof(long)) && version == long.MaxValue)) { version = 1; } else { version += 1; } map.ConcurrencyMap.SetValue(obj, version); } } // update object with database-created values if UpdateAfterWrite is set to true if (map.IsUpdateAfterWrite && (st == StatementType.Insert || st == StatementType.Update)) { if (tr != null) { Refresh(obj, tr); } else { Refresh(obj); } } return(sr); }