/// <summary> /// Updates a data object record using the "table" and a list of column/value pairs. /// </summary> /// <param name="transaction">The transaction to do this as part of.</param> /// <param name="mapping">The mapping of the table or other data container we're dealing with.</param> /// <param name="crit">All records matching this criteria will be updated per the dictionary of /// values.</param> /// <param name="propValues">A dictionary of column/value pairs for all non-ID columns to be updated.</param> /// <returns>The number of records affected.</returns> public override int Update(ITransaction transaction, ClassMapping mapping, DaoCriteria crit, IDictionary<string, object> propValues) { // Since the update might change one of the id fields, we can't just overwrite the // table with new values (since that might be an add). Instead create a temp table, // put in everything that doesn't match, then put in everything that does after // modifying it. DaoCriteria inverseCrit = new DaoCriteria(); foreach (IExpression expr in crit.Expressions) { inverseCrit.Expressions.Add(expr.Invert()); } IDictionary<string, MemoryObject> table = GetTable(mapping); int retVal = 0; lock (table) { IDictionary<string, MemoryObject> tempTable = new Dictionary<string, MemoryObject>(); // First the unchanged records. MemoryDataReader reader = new MemoryDataReader(this, mapping, inverseCrit, table.Values.GetEnumerator()); while (reader.Read()) { MemoryObject unchanged = reader.GetCurrentObject(); tempTable[unchanged.GetKey()] = unchanged; } // Now the changed ones. reader = new MemoryDataReader(this, mapping, crit, table.Values.GetEnumerator()); while (reader.Read()) { MemoryObject changed = reader.GetCurrentObject(); // Set the changed values. foreach (KeyValuePair<string, object> kvp in propValues) { changed.ColValues[kvp.Key] = kvp.Value; } tempTable[changed.GetKey()] = changed; retVal++; } // Now replace the real table contents with the temp ones. table.Clear(); foreach (KeyValuePair<string, MemoryObject> kvp in tempTable) { table.Add(kvp); } } return retVal; }
/// <summary> /// Executes a query and invokes a method with a DataReader of results. /// </summary> /// <param name="transaction">The transaction to do this as part of.</param> /// <param name="mapping">Class mapping for the table we're querying against. Optional, /// but not all columns may be properly typed if it is null.</param> /// <param name="query">The query to execute, should have come from CreateQuery.</param> /// <param name="invokeMe">The method to invoke with the IDataReader results.</param> /// <param name="parameters">A hashtable containing any values that need to be persisted through invoked method. /// The list of objects from the query will be placed here.</param> public override void ExecuteQuery(ITransaction transaction, ClassMapping mapping, IDaQuery query, DataReaderDelegate invokeMe, Hashtable parameters) { // Make a copy of the table and iterate over that, that way reading doesn't block writing (or // more reading). IDictionary<string, MemoryObject> tempTable; IDictionary<string, MemoryObject> table = GetTable(mapping); lock (table) { tempTable = new CheckedDictionary<string, MemoryObject>(table); } MemoryDataReader reader = new MemoryDataReader(this, mapping, ((UnqueryableQuery)query).Criteria, tempTable.Values.GetEnumerator()); try { invokeMe.Invoke(parameters, reader); } finally { reader.Close(); } }
/// <summary> /// Gets a count of records for the given criteria. /// </summary> /// <param name="transaction">The transaction to do this as part of.</param> /// <param name="mapping">The mapping of the table for which to build the query string.</param> /// <param name="crit">The criteria to use for "where" comparisons.</param> /// <returns>The number of results found that matched the criteria.</returns> public override int GetCount(ITransaction transaction, ClassMapping mapping, DaoCriteria crit) { IDictionary<string, MemoryObject> table = GetTable(mapping); int retVal = 0; lock (table) { MemoryDataReader reader = new MemoryDataReader(this, mapping, crit, table.Values.GetEnumerator()); while (reader.Read()) { retVal++; } } return retVal; }
/// <summary> /// Deletes a data object record using the mapping and criteria for what's deleted. /// </summary> /// <param name="transaction">The transaction to do this as part of.</param> /// <param name="mapping">The mapping of the table from which to delete.</param> /// <param name="crit">Criteria for deletion. NOTE: Only the expressions are observed, /// other things (like "order" or start / limit) are ignored. /// WARNING: A null or empty (no expression) criteria will /// delete ALL records!</param> /// <returns>The number of records affected.</returns> public override int Delete(ITransaction transaction, ClassMapping mapping, DaoCriteria crit) { // Find all the records that don't match, and just keep those. DaoCriteria inverseCrit = new DaoCriteria(); foreach (IExpression expr in crit.Expressions) { inverseCrit.Expressions.Add(expr.Invert()); } IDictionary<string, MemoryObject> table = GetTable(mapping); int retVal; lock (table) { int oldCount = table.Count; MemoryDataReader reader = new MemoryDataReader(this, mapping, inverseCrit, table.Values.GetEnumerator()); IDictionary<string, MemoryObject> tempTable = new Dictionary<string, MemoryObject>(); while (reader.Read()) { MemoryObject keeper = reader.GetCurrentObject(); tempTable[keeper.GetKey()] = keeper; } table.Clear(); foreach (KeyValuePair<string, MemoryObject> kvp in tempTable) { table.Add(kvp); } retVal = oldCount - table.Count; } return retVal; }