根据设计当MakeOld后(在读取数据库后,或者手动调用),对记录(SubSonic生成的类)属性附值时,Sonic会检测这个Value是否与原来的不同,只有值不同时才会附值成功,并将该列添加到DirtyColumns,而DirtyColumns中的列才会被Update采用,一般情况下 只要所有列中有一个列的是Dirty==true(被更改过),那么在Save时就会采用Update,
注意:SubSonic中判断是否采用Update判断“全部字段集合”中是否存在一个字段被更改,而生成Update命令时使用的集合是DirtyColumns集合,而不是直接从全部字段集合中查找那些被更改的字段,在多数情况下不会出问题,但有些时候可能带来意想不到的问题,参考下面的场境3。
//=============参考代码1================
public bool IsDirty { get { foreach(TableColumnSetting setting in this) { if(setting.IsDirty) return true; } return false; } //set //{ // foreach (TableColumnSetting setting in this) // setting.IsDirty = value; //} }
//============参考代码2============
public QueryCommand GetSaveCommand(string userName) { if(IsNew) return GetInsertCommand(userName);
if(IsDirty) return GetUpdateCommand(userName);
return null; }
如果您对记录未做任何更改而直接调用 .Save()时会根据IsNew与IsDirty的取值来决定采用Insert或Update。
如果两个多是false,那么就返回null.那么Save操作将什么都不做。
//============参考代码3============
QueryCommand cmd = GetSaveCommand(userName); if(cmd == null) return;
场境1:
Employe emp=new Employe(1);//加载一个员工数据
//这个时候 IsNew=false,IsDirty=false
emp.Name=emp.Name; //没有改变
emp.Save();//这里的Save方法将不做任何处理
场境2:
Employe emp=new Employe(1);
emp.Name=txtName.txt;//假设您在文本框中调整了Name取值
//这个时候 isNew=false;IsDirty=true;
emp.Save();将使用Update,并且只更新Name字段。
场境3:(报错)
Employe emp=new Employe(1);
Employe backEmp=new Employe();
backEmp.CopyFrom(backEmp);
//copyFrom后会backEmp.IsDirty全部是true
//参考代码7
backEmp.Name="xxxx";
backEmp.MackOld();//将IsNew设置成False
backEmp.Save(); //报错,IsDirty=True,而DirtyColumns为空,
//生成 Update Employe Set Where EmpoyeId=1 这样的错误TSQL
场境4:(报错)
Employe emp=new Employe(1);
Employe backEmp=new Employe();
backEmp.CopyFrom(backEmp);
backEmp.MackOld();
backEmp.Name=backEmp.Name;
backEmp.Save();//这时IsDirty是True,而DirtyColumns为空
正确作法,应该在backEmp.MackOld();后再调用backEmp.MackClear();
//=============参考代码8=================
///
/// Called after any property is set. Sets IsDirty to true . /// public void MarkClean() { foreach(TableSchema.TableColumnSetting setting in columnSettings) setting.IsDirty = false; DirtyColumns.Clear(); }//========参考代码4==========
///
/// Called after Update() invokation. Sets IsNew to false . /// public void MarkOld() { IsLoaded = true; _isNew = false; }//========参考代码5======================
///
/// Copies the passed-in instance settings to this instance /// /// The copy instance. public void CopyFrom(T copyInstance) { if(copyInstance == null) throw new ArgumentNullException("copyInstance");foreach(TableSchema.TableColumnSetting setting in copyInstance.columnSettings) SetColumnValue(setting.ColumnName, setting.CurrentValue); }
//========参考代码6======================
///
/// Sets a value for a particular column in the record /// /// Name of the column, as defined in the database /// The value to set the type to public void SetColumnValue(string columnName, object oValue) { columnSettings = columnSettings ?? new TableSchema.TableColumnSettingCollection();// add the column to the DirtyColumns // if this instance has already been loaded // and this is a change to existing values if(IsLoaded && !IsNew) { TableSchema.Table schema = GetSchema(); object oldValue = null; string oldValueMsg = "NULL"; string newValueMsg = "NULL"; bool areEqualOrBothNull = false;
try { oldValue = columnSettings.GetValue(columnName); } catch {}
if(oldValue == null && oValue == null) areEqualOrBothNull = true; else { if(oldValue != null) { oldValueMsg = oldValue.ToString(); areEqualOrBothNull = oldValue.Equals(oValue); }
if(oValue != null) newValueMsg = oValue.ToString(); }
TableSchema.TableColumn dirtyCol = schema.GetColumn(columnName);
if(dirtyCol != null && !areEqualOrBothNull) { string auditMessage = String.Format("Value changed from {0} to {1}{2}", oldValueMsg, newValueMsg, Environment.NewLine); TableSchema.TableColumn dirtyEntry = DirtyColumns.GetColumn(columnName); if(dirtyEntry != null) { DirtyColumns.Remove(dirtyEntry); auditMessage = String.Concat(dirtyCol.AuditMessage, auditMessage); }
dirtyCol.AuditMessage = auditMessage; DirtyColumns.Add(dirtyCol); } }
columnSettings.SetValue(columnName, oValue);//这里最终调用参考代码7
}
//============参考代码7============
///
/// Gets or sets the current value. /// /// The current value. public object CurrentValue { get { return _currentValue; } set { if(value == null && _currentValue == null) return;if(value != null) { if(value.Equals(_currentValue)) return; }
_currentValue = value; _isDirty = true; } }