使用Subsonic与ObjectDataSource(ODS)

    技术2025-01-20  4

       Subsonic,在小型项目应用中,作为数据库访问层相当方便,而很多快速开发中我们一般会使用GridView + ObjectDataSrouce ,基本上是一拖一放就能解决很多问题,当然如果你平时注意收据一些样式或皮肤文件,那么做出来的界面也很不错,总之一句话,"太方便了!".

      一般使用SubStage生成代码后,每张表,如名为:Rule的表会生成一个叫RuleController的来,这个来是用来绑定ODS用的,

     下面是生成Rule表的Update方法,         [DataObjectMethod(DataObjectMethodType.Update, true)]      public void Update(int Id,string Name,string ReplaceText,string ReplaceMode,string Pattern,bool? IsRegex,bool? Enabled,string Username)      {       Rule item = new Rule();          item.MarkOld(); //设置为更新模式,即IsNew=false; IsLoaded=True,这样save时对应的SQL为Update          item.IsLoaded = true; //貌似这句跟上面一样          item.Id = Id;         item.Name = Name;         item.ReplaceText = ReplaceText;         item.ReplaceMode = ReplaceMode;         item.Pattern = Pattern;         item.IsRegex = IsRegex;         item.Enabled = Enabled;         item.Username = Username;               item.Save(UserName);      }

     可以看到Update方法中的参数列表跟数据库中表的列1,1对应,一般情况下我们不会在gridview中包括全部列,如文章内容列这些不会在gridview中显示,而是放到一个专门的页面上来处理,那么粗看Update代码也许会有这样的困惑:

    我在gridview上只双向帮定(bind) Name(参考上面代码),IsRegex 两个列,其他列要么不显示,要么只读(注意Id为主键,页面上的geidview 设置DataKeyNames="ID"),这样每次触发Update时,gridview只把双向帮定的数据跟ID发给ODS,而其他列多为null,那么Update 中的item.Save(UserName)会不会出现把数据库中不需要更新的列设置为null呢?

      在使用数据库跟踪后发现没有出现我上面担心问题,subsonic生成的update一般为 update [表名] Set 双向绑定列1=value1,双向绑定列2=value2... Where Id=valueid.  查找项目提供的代码发现,设置属性时(如item.Username=Username)会调用定义在RecordBase.cs中的SetColumnValue(string columnName,object oValue)来进行,代码如下

    -------------------------------------

     

      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);         }

    ------------------------------

     从上面代码可以看到,当传入的oValue为null,并且oldValue也为null时,ActiveRecord是不会把这个列加入到DirtyColumns中的,而DirtyColumns中的列则是生成SQL语句Update 中 Set 后具体更新的列.  RuleController(参考上面)中的Update中首先Rule item= new Rule() 这样的结果是全部列的oldValue也为null(因为Rule为参构造函数创建类后不会进行读书记库操作,因此columnSettings中的全部列值多为null,这样就保证Save时不会把null列覆盖到原来的列, 另外要注意的是,为了保证能把null专递到 RuleController的Update中,Update的值类型参数多为可空类型(如?int,?bool...) 这样当gridview没传递相应列值时---没双向绑定或不是主键(也有可能是没在gridview中设置)ODS就会根据配置的参数列表传递一个null过去.     另外你可以在ODS的Updateing ,Selecting事件中设置具体的参数值,在gridview + ods + 数据访问类 这样的三层结构中,数据需要层层传递,同时也意味着一个修改或说控制可以安排在这三层的任意一层,前面两层一般使用控件提供的事件而最后一层是自己编写的类.

     最后一般注意下ODS的OldValuesParameterFormatString 设置,在使用subsonic时设置为{0}, 下面为MSDN的描述:

     

    OldValuesParameterFormatString 格式字符串只应用于主键,例如,由相关联的数据绑定控件的 DataKeyNames 属性所标识的主键,或者用在以下删除方案和更新方案中:ConflictDetection 属性设置为 CompareAllValues 值,并且一组 oldValues 值传递给了相应的数据方法。这种情况下,此格式字符串应用于 oldValues 集合中的每个参数名。

    在以下两种常见方案中,您可能要更改 OldValuesParameterFormatString 属性:

    在更新中区别旧值和新值。ConflictDetection 属性设置为 CompareAllValues 值时,原始值和新值的参数都被添加到 UpdateParameters 集合中。如果没有设置字符串的格式,将为每个数据字段创建两个同名参数。通过更改原始值参数的名称,可以将数据与原始数据源进行比较,以检测冲突并比较键值。

    某些可视化设计器实现了特定的原始值和键命名方案。

     

    最新回复(0)