/// <summary> /// Inserts the specified object. /// </summary> /// <param name="obj">The object.</param> /// <param name="selectBack">The <see cref="Zonkey.SelectBack"/> value that determines which rows, if any, to return.</param> /// <returns>A <see cref="SaveResultStatus"/> value based on the outcome of the insert operation.</returns> public SaveResult TryInsert(T obj, SelectBack selectBack) { try { DoBeforeSave(SaveType.Insert, obj); DbCommand[] commands = CommandBuilder.GetInsertCommands(obj, selectBack); DbCommand readerCommand = commands[commands.Length - 1]; if ((selectBack == SelectBack.None) || (commands.Length == 2)) { int nRecordsAffected = ExecuteNonQueryInternal(commands[0]); /* KB 1/19/12: This seems moot at this point so it's being removed * if ((nRecordsAffected != 1) && (!IgnoreUpdateRowCount)) * return new SaveResult(SaveResultStatus.Fail, SaveType.Insert, nRecordsAffected); */ if (selectBack == SelectBack.None) { return(new SaveResult(SaveResultStatus.Success, SaveType.Insert, nRecordsAffected)); } } using (DbDataReader reader = ExecuteReaderInternal(readerCommand, CommandBehavior.SingleRow)) { if (reader.Read()) { PopulateSingleObject(obj, reader, false); return(new SaveResult(SaveResultStatus.Success, SaveType.Insert, reader.RecordsAffected)); } return(new SaveResult(SaveResultStatus.Fail, SaveType.Insert, reader.RecordsAffected)); } } catch (DataException) { throw; } catch (Exception ex) { throw new DataException(ex.Message, ex); } }
/// <summary> /// Inserts the specified object. /// </summary> /// <param name="obj">The object.</param> /// <param name="selectBack">The <see cref="Zonkey.SelectBack"/> value that determines which rows, if any, to return.</param> /// <returns>A <see cref="Zonkey.SaveResult"/> value based on the outcome of the insert operation.</returns> public SaveResult TryInsert(T obj, SelectBack selectBack) { try { DbCommand[] commands = CommandBuilder.GetInsertCommands(obj, selectBack); DbCommand readerCommand = commands[commands.Length - 1]; if ((selectBack == SelectBack.None) || (commands.Length == 2)) { int nRecordsAffected = ExecuteNonQueryInternal(commands[0]); if (nRecordsAffected != 1) { return(SaveResult.Fail); } if (selectBack == SelectBack.None) { return(SaveResult.Success); } } using (DbDataReader reader = ExecuteReaderInternal(readerCommand, CommandBehavior.SingleRow)) { if (reader.Read()) { PopulateSingleObject(obj, reader, false); return(SaveResult.Success); } return(SaveResult.Fail); } } catch (DataException) { throw; } catch (Exception ex) { throw new DataException(ex.Message, ex); } }
/// <summary> /// Tries to save the object /// </summary> /// <param name="obj">The object to save</param> /// <param name="criteria">The criteria of type <see cref="Zonkey.UpdateCriteria"/>.</param> /// <param name="affect">The <see cref="Zonkey.UpdateAffect"/> value that determines which rows to affect.</param> /// <param name="selectBack">The <see cref="Zonkey.SelectBack"/> value that determines whether to select back the changed rows.</param> /// <returns>A value of type <see cref="Zonkey.SaveResult"/></returns> public SaveResult TrySave(T obj, UpdateCriteria criteria, UpdateAffect affect, SelectBack selectBack) { var objSV = obj as ISavable; if (objSV == null) { throw new ArgumentException("Save() is only supported on classes that implement Zonkey.ObjectModel.ISavable", "obj"); } var objDCX = obj as DataClass; // raise pre-save event if (objDCX != null) { objDCX.OnBeforeSave(); } SaveResult result; switch (objSV.DataRowState) { case DataRowState.Added: result = TryInsert(obj, selectBack); _lastSaveSuccessType = 1; break; case DataRowState.Detached: throw new InvalidOperationException("Cannot save objects in a detached state. Did you forget to use the new record constructor?"); case DataRowState.Modified: if (((selectBack == SelectBack.None) || (selectBack == SelectBack.AllFields)) && (criteria <= UpdateCriteria.ChangedFields) && (affect == UpdateAffect.ChangedFields)) { result = TryUpdate2(obj, criteria, (selectBack == SelectBack.AllFields)); } else { result = TryUpdate(obj, criteria, affect, selectBack); } _lastSaveSuccessType = 2; break; default: return(SaveResult.Skipped); } // raise post-save event and commit values if (result == SaveResult.Success) { if (objDCX != null) { objDCX.OnAfterSave(true); } objSV.CommitValues(); } return(result); }
/// <summary> /// Inserts the specified obj. /// </summary> /// <param name="obj">The obj.</param> /// <param name="selectBack">The select back.</param> /// <returns></returns> public bool Insert(T obj, SelectBack selectBack) { return(HandleSaveResult(TryInsert(obj, selectBack))); }
/// <summary> /// Saves the specified object /// </summary> /// <param name="obj">The object to save</param> /// <param name="criteria">The criteria of type <see cref="Zonkey.UpdateCriteria"/>.</param> /// <param name="affect">The <see cref="Zonkey.UpdateAffect"/> value that determines which rows to affect.</param> /// <param name="selectBack">The <see cref="Zonkey.SelectBack"/> value that determines whether to select back the changed rows.</param> /// <returns>true/false</returns> public bool Save(T obj, UpdateCriteria criteria, UpdateAffect affect, SelectBack selectBack) { return(HandleSaveResult(TrySave(obj, criteria, affect, selectBack))); }
/// <summary> /// Tries to update the specified object /// </summary> /// <param name="obj">The object.</param> /// <param name="criteria">The criteria of type <see cref="Zonkey.UpdateCriteria"/>.</param> /// <param name="affect">The <see cref="Zonkey.UpdateAffect"/> value that determines which rows to affect.</param> /// <param name="selectBack">The <see cref="Zonkey.SelectBack"/> value that determines whether to select back the changed rows.</param> /// <returns>A <see cref="Zonkey.SaveResult"/> value based on the outcome of the update operation.</returns> public SaveResult TryUpdate(T obj, UpdateCriteria criteria, UpdateAffect affect, SelectBack selectBack) { try { DbCommand[] commands = CommandBuilder.GetUpdateCommands(obj, criteria, affect, selectBack); return(UpdateInternal(obj, commands, (selectBack != SelectBack.None))); } catch (DataException) { throw; } catch (Exception ex) { throw new DataException(ex.Message, ex); } }
/// <summary> /// Saves the collection. /// </summary> /// <param name="collection">The collection.</param> /// <param name="criteria">The criteria of type <see cref="Zonkey.UpdateCriteria"/>.</param> /// <param name="affect">The <see cref="Zonkey.UpdateAffect"/> value that determines which rows to affect.</param> /// <param name="selectBack">The <see cref="Zonkey.SelectBack"/> value that determines whether to select back the changed rows.</param> /// <returns>A value of type <see cref="T:Zonkey.CollectionSaveResult"/></returns> public CollectionSaveResult <T> TrySaveCollection(ICollection <T> collection, UpdateCriteria criteria, UpdateAffect affect, SelectBack selectBack) { var colResult = new CollectionSaveResult <T>(); var bindCol = collection as ITrackDeletedItems <T>; if (bindCol != null) { foreach (T obj in bindCol.DeletedItems) { var objSV = obj as ISavable; if (objSV != null) { if (objSV.DataRowState == DataRowState.Deleted) { DeleteItem(obj); colResult.Deleted.Add(obj); } else { colResult.Skipped.Add(obj); } } else { colResult.Failed.Add(obj); } } } foreach (T obj in collection) { var objSV = obj as ISavable; if (objSV != null) { if (objSV.DataRowState != DataRowState.Unchanged) { switch (TrySave(obj, criteria, affect, selectBack)) { case SaveResult.Skipped: colResult.Skipped.Add(obj); break; case SaveResult.Conflict: colResult.Conflicted.Add(obj); break; case SaveResult.Fail: colResult.Failed.Add(obj); break; case SaveResult.Success: if (_lastSaveSuccessType == 1) { colResult.Inserted.Add(obj); } else { colResult.Updated.Add(obj); } break; } } else { colResult.Skipped.Add(obj); } } else { colResult.Failed.Add(obj); } } return(colResult); }
/// <summary> /// Saves the collection. /// </summary> /// <param name="collection">The collection.</param> /// <param name="criteria">The criteria.</param> /// <param name="affect">The affect.</param> /// <param name="selectBack">The select back.</param> /// <returns></returns> public int SaveCollection(ICollection <T> collection, UpdateCriteria criteria, UpdateAffect affect, SelectBack selectBack) { var result = TrySaveCollection(collection, criteria, affect, selectBack); if ((result.Conflicted.Count > 0) || (result.Failed.Count > 0)) { throw new CollectionSaveException <T>(result); } return(result.Inserted.Count + result.Updated.Count); }
public DbCommand[] GetInsertCommands(object obj, SelectBack selectBack) { DbCommand command1 = GetTextCommand(""); var intoString = new StringBuilder(); var valuesString = new StringBuilder(); var setParmList = new List <DbParameter>(); var whereString = new StringBuilder(); var whereParmList = new List <DbParameter>(); var selectString = new StringBuilder(); // set select back default if (selectBack == SelectBack.Default) { selectBack = (_dataMap.DataItem.SelectBack == SelectBack.Default) ? SelectBack.UnchangedFields : _dataMap.DataItem.SelectBack; } foreach (IDataMapField field in _dataMap.DataFields) { PropertyInfo pi = field.Property; if (pi == null) { continue; } string sFieldDescr = _dialect.FormatFieldName(field.FieldName, (field.UseQuotedIdentifier ?? UseQuotedIdentifier)); if (field.IsAutoIncrement) { if (field.IsKeyField) { if (whereString.Length > 0) { whereString.Append(" AND "); } whereString.Append(sFieldDescr); whereString.Append(" = "); whereString.Append(_dialect.FormatAutoIncrementSelect(field.SequenceName)); // special case to handle bad access behavior on identity keys if ((_dialect is Dialects.AccessSqlDialect) && (selectBack > SelectBack.IdentityOrVersion)) { selectBack = SelectBack.IdentityOrVersion; } } // supports identity only select-back if (selectString.Length > 0) { selectString.Append(", "); } selectString.Append(_dialect.FormatAutoIncrementSelect(field.SequenceName)); selectString.Append(" AS "); selectString.Append(sFieldDescr); continue; } if (field.IsKeyField) { DbParameter whereParam = CreateWhereParam(command1, field); if (whereString.Length > 0) { whereString.Append(" AND "); } whereString.Append(sFieldDescr); whereString.Append(" = "); whereString.Append(whereParam.ParameterName); whereParam.Value = pi.GetValue(obj, null); whereParmList.Add(whereParam); } if ((field.IsRowVersion) || (field.AccessType == AccessType.ReadOnly)) { continue; } object oValue = pi.GetValue(obj, null); if ((oValue == null) && (!field.IsNullable)) { continue; } if ((oValue is Guid) && (Guid.Empty == (Guid)oValue)) { continue; } DbParameter parm = CreateSetParam(command1, field); if (pi.PropertyType == typeof(string)) { parm.Value = (oValue ?? _nullStringDefault); } else { parm.Value = (oValue ?? DBNull.Value); } if (intoString.Length > 0) { intoString.Append(", "); valuesString.Append(", "); } intoString.Append(sFieldDescr); valuesString.Append(parm.ParameterName); setParmList.Add(parm); } if (intoString.Length == 0) { throw new InvalidOperationException(String.Format("Class '{0}' does not contain any properties with DataFieldAttribute(s) or all fields are ReadOnly.", _dataObjectType.FullName)); } command1.CommandText = string.Format("INSERT INTO {0} ({1}) VALUES ({2}); ", SaveToTable, intoString, valuesString); command1.Parameters.AddRange(setParmList.ToArray()); if (selectBack != SelectBack.None) { string sSql2; if ((selectBack == SelectBack.IdentityOrVersion) && (selectString.Length > 0)) { sSql2 = string.Concat("SELECT ", selectString); } else if (whereString.Length == 0) { throw new InvalidOperationException(String.Format("Class '{0}' does not contain any properties with DataFieldAttributes or none are marked with IsKeyField.", _dataObjectType.FullName)); } else { sSql2 = string.Format("SELECT {0} FROM {1} WHERE {2}; ", ColumnsString, TableName, whereString); } if (_dialect.UseSqlBatches) { command1.CommandText += sSql2; command1.Parameters.AddRange(whereParmList.ToArray()); } else { DbCommand command2 = GetTextCommand(sSql2); command2.Parameters.AddRange(whereParmList.ToArray()); return(new[] { command1, command2 }); } } return(new[] { command1 }); }
public DbCommand[] GetUpdateCommands(object obj, UpdateCriteria criteria, UpdateAffect affect, SelectBack selectBack) { if (obj == null) { throw new ArgumentNullException("obj"); } if (obj.GetType() != _dataObjectType) { throw new ArgumentException("Type of 'obj' does not match type from constructor."); } // set update criteria - default is changed fields if (criteria == UpdateCriteria.Default) { criteria = (_dataMap.DataItem.UpdateCriteria == UpdateCriteria.Default) ? UpdateCriteria.ChangedFields : _dataMap.DataItem.UpdateCriteria; } if ((criteria == UpdateCriteria.KeyAndVersion) && (!_dialect.SupportsRowVersion)) { criteria = UpdateCriteria.ChangedFields; } // set select back default if (selectBack == SelectBack.Default) { selectBack = (_dataMap.DataItem.SelectBack == SelectBack.Default) ? SelectBack.UnchangedFields : _dataMap.DataItem.SelectBack; } // get savable obj var objSV = obj as ISavable; if (objSV == null) { affect = UpdateAffect.AllFields; if (selectBack == SelectBack.UnchangedFields) { selectBack = SelectBack.AllFields; } if (criteria == UpdateCriteria.ChangedFields) { criteria = UpdateCriteria.KeyOnly; } } // init command array DbCommand updateCommand = GetTextCommand(""); // create string builders and param lists var setString = new StringBuilder(); var setParmList = new List <DbParameter>(); var whereString = new StringBuilder(); var whereParmList = new List <DbParameter>(); var selectString = new StringBuilder(); var keyString = new StringBuilder(); var keyParmList = new List <DbParameter>(); foreach (IDataMapField field in _dataMap.DataFields) { PropertyInfo pi = field.Property; if (pi == null) { continue; } bool hasChanged = (objSV != null) ? HasFieldChanged(pi, objSV) : true; string sFieldDescr = _dialect.FormatFieldName(field.FieldName, (field.UseQuotedIdentifier ?? UseQuotedIdentifier)); if (selectBack > SelectBack.None) { if (field.IsKeyField) { DbParameter keyParam = CreateWhereParam(updateCommand, field); if (keyString.Length > 0) { keyString.Append(" AND "); } keyString.Append(sFieldDescr); keyString.Append(" = "); keyString.Append(keyParam.ParameterName); keyParam.Value = pi.GetValue(obj, null); keyParmList.Add(keyParam); } else if ((selectBack == SelectBack.AllFields) || ((selectBack == SelectBack.UnchangedFields) && (!hasChanged)) || ((selectBack >= SelectBack.IdentityOrVersion) && (field.IsRowVersion))) { if (selectString.Length > 0) { selectString.Append(", "); } selectString.Append(sFieldDescr); } } if (field.IsKeyField || (hasChanged && (criteria >= UpdateCriteria.ChangedFields)) || (field.IsRowVersion && (criteria == UpdateCriteria.KeyAndVersion)) ) { // A primary key or row version if (whereString.Length > 0) { whereString.Append(" AND "); } // get value for parameter object oParmValue; if ((objSV != null) && (objSV.OriginalValues.ContainsKey(pi.Name))) { oParmValue = (objSV.OriginalValues[pi.Name] ?? DBNull.Value); } else { oParmValue = (pi.GetValue(obj, null) ?? DBNull.Value); } // add to command if (Convert.IsDBNull(oParmValue)) { whereString.AppendFormat("{0} IS NULL", sFieldDescr); } else if (!field.IsComparable) { whereString.AppendFormat("{0} IS NOT NULL", sFieldDescr); } else { DbParameter whereParam = CreateWhereParam(updateCommand, field); whereString.Append(sFieldDescr); whereString.Append(" = "); whereString.Append(whereParam.ParameterName); whereParam.Value = oParmValue; whereParmList.Add(whereParam); } } if ((field.IsAutoIncrement) || (field.IsRowVersion) || (field.AccessType == AccessType.ReadOnly)) { continue; } if ((affect == UpdateAffect.ChangedFields) && (!hasChanged)) { continue; } if (setString.Length > 0) { setString.Append(", "); } DbParameter setParm = CreateSetParam(updateCommand, field); setString.Append(sFieldDescr); setString.Append(" = "); setString.Append(setParm.ParameterName); setParm.Value = (pi.GetValue(obj, null) ?? DBNull.Value); setParmList.Add(setParm); } if (setParmList.Count == 0) { return(null); } if (whereString.Length == 0) { throw new InvalidOperationException(String.Format("Class '{0}' does not contain any properties with DataFieldAttributes or none are marked with IsKeyField.", _dataObjectType.FullName)); } updateCommand.CommandText = String.Format("UPDATE {0} SET {1} WHERE {2};", SaveToTable, setString, whereString); updateCommand.Parameters.AddRange(setParmList.ToArray()); updateCommand.Parameters.AddRange(whereParmList.ToArray()); if ((selectBack > SelectBack.None) && (selectString.Length > 0)) { if (keyString.Length == 0) { throw new InvalidOperationException(String.Format("Class '{0}' does not contain any properties with DataFieldAttributes or none are marked with IsKeyField.", _dataObjectType.FullName)); } DbCommand selectCommand = GetTextCommand(""); selectCommand.CommandText = String.Format("SELECT {0} FROM {1} WHERE {2};", selectString, TableName, keyString); selectCommand.Parameters.AddRange(keyParmList.ToArray()); return(new[] { updateCommand, selectCommand }); } // return null index 1 to indicate no select-back return(new[] { updateCommand, null }); }
/// <summary> /// Equivalent to calling DataClassAdapter.Save /// </summary> /// <typeparam name="Tdc">The type of the dc.</typeparam> /// <param name="obj">The obj.</param> /// <param name="updateCriteria">The update criteria</param> /// <param name="updateAffect">Affect which fields</param> /// <param name="selectBack">Select what back</param> /// <returns></returns> public virtual bool Save <Tdc>(Tdc obj, UpdateCriteria updateCriteria, UpdateAffect updateAffect, SelectBack selectBack) where Tdc : class, ISavable, new() { return(Adapter <Tdc>().Save(obj, updateCriteria, updateAffect, selectBack)); }
/// <summary> /// Saves the collection. /// </summary> /// <param name="collection">The collection.</param> /// <param name="criteria">The criteria of type <see cref="Zonkey.UpdateCriteria"/>.</param> /// <param name="affect">The <see cref="Zonkey.UpdateAffect"/> value that determines which rows to affect.</param> /// <param name="selectBack">The <see cref="Zonkey.SelectBack"/> value that determines whether to select back the changed rows.</param> /// <param name="continueOnError">if set to <c>true</c> continues past errors.</param> /// <returns> /// A value of type <see cref="Zonkey.CollectionSaveResult{T}"/> /// </returns> public CollectionSaveResult <T> TrySaveCollection(ICollection <T> collection, UpdateCriteria criteria, UpdateAffect affect, SelectBack selectBack, bool continueOnError) { var colResult = new CollectionSaveResult <T>(); var bindCol = collection as ITrackDeletedItems <T>; if (bindCol != null) { foreach (T obj in bindCol.DeletedItems) { var objSV = obj as ISavable; if (objSV != null) { if (objSV.DataRowState == DataRowState.Deleted) { try { DeleteItem(obj); } catch (Exception ex) { colResult.Exceptions.Add(new CollectionSaveExceptionItem <T>(obj, ex)); if (!continueOnError) { throw; } } colResult.Deleted.Add(obj); } else { colResult.Skipped.Add(obj); } } else { colResult.Failed.Add(obj); } } } foreach (T obj in collection) { var objSV = obj as ISavable; if (objSV != null) { if (objSV.DataRowState != DataRowState.Unchanged) { try { SaveResult saveResult = TrySave(obj, criteria, affect, selectBack); switch (saveResult.Status) { case SaveResultStatus.Skipped: colResult.Skipped.Add(obj); break; case SaveResultStatus.Conflict: colResult.Conflicted.Add(obj); break; case SaveResultStatus.Fail: colResult.Failed.Add(obj); break; case SaveResultStatus.Success: if (saveResult.SaveType == SaveType.Insert) { colResult.Inserted.Add(obj); } else { colResult.Updated.Add(obj); } break; } } catch (Exception ex) { colResult.Exceptions.Add(new CollectionSaveExceptionItem <T>(obj, ex)); if (!continueOnError) { throw; } } } else { colResult.Skipped.Add(obj); } } else { colResult.Failed.Add(obj); } } return(colResult); }
/// <summary> /// Saves the collection. /// </summary> /// <param name="collection">The collection.</param> /// <param name="criteria">The criteria of type <see cref="Zonkey.UpdateCriteria"/>.</param> /// <param name="affect">The <see cref="Zonkey.UpdateAffect"/> value that determines which rows to affect.</param> /// <param name="selectBack">The <see cref="Zonkey.SelectBack"/> value that determines whether to select back the changed rows.</param> /// <returns>A value of type <see cref="Zonkey.CollectionSaveResult{T}"/></returns> public CollectionSaveResult <T> TrySaveCollection(ICollection <T> collection, UpdateCriteria criteria, UpdateAffect affect, SelectBack selectBack) { return(TrySaveCollection(collection, UpdateCriteria.Default, UpdateAffect.ChangedFields, SelectBack.Default, false)); }