예제 #1
0
        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);
        }
예제 #2
0
        /// <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);
        }