.NET中的视图和过滤器 (DefaultView和RowFilter)
NET中的视图和过滤器 (DefaultView和RowFilter)
在实际应用中,这些对象大多会对诸如SQL Server一类的关系型数据库中的数据进行操作。但是,它们可以处理各种数据,而不管它的物理存储媒介。
你可以使用DataSet对象来打包和关联各表中的数据,用DataTable类来处理表格类型的数据,而DataRow对象可以处理表中某一行的数据。
这三个对象都是对数据进行打包,但有不同的逻辑聚合层次。DataSet是DataTable和其他的组合。而DataTable是DataRow和其他的组合。DataRow是字段和其他的组合。但是这些对象中都没有内建过滤和排序的功能。
ADO.NET提供了一些类来处理这个数据库应用程序中的重要方面。在.Net Beta2中,这方面最重要的两个对象就是DataView和DataViewManager。
注意:DataViewManager是Beta2中特有的。在Beta1中,相应的功能由DataSetView完成。
DataView类用来表示定制的DataTable的视图。DataTable和DataView的关系是遵循著名的设计模式--文档/视图模式,其中DataTable是文档,而Dataview是视图。
在任何时候,你都可以有多个基于相同数据的不同的视图。更重要的是,你可以对每一个具有自己一套属性、方法、事件的视图作为独立的对象进行处理。这也代表了相对ADO一个巨大的飞跃。
ADO Recordset可以定义过滤字符串。一旦你建立了该字符窜,只有匹配特定标准的数据才能够进行读写。Filter属性的工作原理同动态WHERE子句很相似。它只是简单的在同一recordset对象视图上隐藏了某些记录。
在ADO中,你从没有一个独立的视图对象。一个过滤过的recordset总是同一个对象,只不过显示出的记录比它实际数量少一些而已。
如果你不需要同时处理一些不同的视图,上述问题并不要紧。编程接口赋予了recordset既可以是表也可以是视图的功能。但是在创建时,这不能同时发生。在某一特定时刻,recordset只能是没有过滤字符串的表或者是激活了过滤字符串的视图。
Recordset的克隆提供了较好解决这个结构限制的方法。正如Clonation and the Case of Table Dolly, Part 1中所说的,克隆recordset相对开销较少,因为它不复制数据,只是复制recordset的基本构造。要处理同一数据两个或两个以上的视图,你可以利用两个或两个以上克隆,各自有一套相应的过滤字符串。
在ADO.NET中,你可以使用新型对象模型所提供的DataView对象。ADO.NET的DataView对象用来表示给定数据表的定制的视图,但你可以像处理单独的对象一样处理它。DataView对象保留了对表的一个引用并允许对它进行更新。
功能上而言,使用ADO Recordset克隆与使用特殊的视图对象完成的是同样的功能,都是让你实现过滤,对所选的数据行进行操作,并同时处理多个视图。
DataView对象继承了MarshalByValueComponent并实现了一组接口使之在数据绑定控件中可用。 Public Class DataView
Inherits MarshalByValueComponent
Implements IBindingList, IList, ICollection,IEnumerable, _
ITypedList, ISupportInitialize
DataView中的内容可以通过许多编程接口进行操作,包括集合,列表和枚举器。IBindingList接口确保了该类提供所有用来支持复杂的和简单的数据绑定的必要特征。
总的来说,DataView对象可以用来达到两个目的。第一,视图对于关联DataTable对象和数据绑定控件中的DataSource域是很重要的。第二,它也对连接的DataTable提供了一层包装,让你能够进行过滤,排序,编辑和浏览。
DataView并不是唯一的可以通过传值进行远程操作的数据驱动类。DataSet和DataTable也具有同样的能力,特别是在互操作的场景下。
public DataView(DataTable);
DataView dv;
dv = new DataView(theDataSet.Tables["Employees"]);
DataView dv = new DataView();
dv.Table = theDataSet.Tables["Employees"];
DataView构造函数使你由DataTable中得到一个DataView对象。如果需要,反之亦可。事实上,DataTable对象的DefaultView属性返回一个该表的DataView对象。
DataView dv = dt.DefaultView;
Sort
前者可以定制视图中可见数据应匹配的规则。而后者通过表达式来进行排序。当然你可以使用这两者的任意组合。
public virtual string RowFilter {get; set;}
dv.RowFilter = "EmployeeID >5 AND Birthdate < #1/31/82#"
dv.RowFilter = "Description LIKE '*product*'"
过滤字符串是表达式的逻辑连接。可以用AND,OR,NOT来连接成一个较短的表达式,也可以使用圆括号来组成子句,指定优先的运算。
通常包含列名的子句同字母、数字、日期或另一个列名进行比较。这里,可以使用关系运算符和算术运算符,如>=, <, >, +, *, % (取模)等等。
如果要选取的行并不能方便地通过算术或逻辑运算符表达,你可以使用IN操作符。以下代码显示如何选取一个随机行:
dv.RowFilter = "employeeID IN (2,4,5)"
请注意,如果在LIKE子句中已经有了*或%字符,你必须用方括号将其括起,以免歧义。如果很不幸,字符串中方括号本身也存在了,那么它也必须用将本身括起。这样,匹配语句会如下所示:
dv.RowFilter = "Description LIKE '[[]*[]]product[[]*[]]"
dv.RowFilter = "Description LIKE 'prod*ct"
RowFilter也支持聚合函数,如SUM, COUNT, MIN,MAX, and AVG。如果表中没有数据行,那么函数将返回NULL。
在介绍RowFilter表达式的最后,让我们讨论三个很便利的函数:Len,IIF和Substring。
正如其名,Len()返回特定表达式的长度。该表达式可以是一个列名,也可以是其他合法的表达式。
Substring()返回指定的表达式自特定位置开始,特定长度的字符子串。
我最喜欢用的是IIF(),它按照逻辑表达式的值有一到两个值。IIF是IF-THEN-ELSE语句的紧凑表达。语法如下:
IIF(expression, if_true, if_false)
IIF(employeeID<6, Len(lastname) %2 =0, Len(lastname) %2 >0)
例子程序是一个Windows® Form应用程序,其中使用了两个datagrid
控件来实现master/detail结构。一个grid在载入时生成,即在SQL
Server data adapter完成数据读取工作之后。请注意,data
adapter是Beta 2中引入的,在Beta 1中相应的是SQLDataSetCommand类。
在上面的举例中,datagrid必须负责预排视图中的数据行,以便刷新用户界面。这个自动机制是.NET
数据绑定的产物。Datagrid是通过DataSource属性来获取数据的数据绑定控件。DataView是一个可数据绑定的类,可构建DataSource属性的内容。
dv = ds.Tables["Employees"].DefaultView;
dv.RowFilter = "employeeid >5";
String buf = new String();
DataRowView dr = New DataRowView();
foreach(dr in dv)
buf = "";
buf &= dr("lastname").ToString()& ", " & dr("firstName").ToString();
ListBox1.Items.Add(buf);
}
要访问视图中某一行,可以使用DataRowView类。DataRowView可表示DataRow的视图,就像DataView表达DataTable定制的视图一样。
总的来说,DataRow最多有四种状态:default,original,current和proposed。这些状态由DataRowVersion枚举类型设置,由RowVersion属性表达。
DataRow的视图只能是其中某一种状态。
数据行的默认(default)版本只有当其列在构造时设定了默认值时才有。而初始(original)版本是指在最后一次调用表的AcceptChanges后,从数剧源中得到数据行或快照。当前(Current)版本是指当前的数据行,包括所有当时发生的更新。Proposed状态只存在于调用BeginEdit和EndEdit的编辑过程中。
可以通过访问DataRow相同的语法访问DataRowView。这里最重要的属性叫Item。
DataView支持Sort属性,可以用来对视图中的内容排序。Sort由用逗号分隔的列名表达式进行排序。通过在任何列名后加ASC或者DESC限定词,可以使得字段按照上升或者下降的顺序排列。如果没有方向限定词,默认顺序为ASC。
DataView是内存中的对象,所以排序在本地进行,无需调用数据库服务器。
RowStateFilter是DataView另一有趣的属性。它可以用任何预定义的标准来过滤DataTable中的内容。下表中是DataViewRowState枚举类型的所有取值: CurrentRows 包括所有未更新的、新的和修改的数据行
Deleted 所有自上次调用AcceptChanges后删除的数据行
ModifiedCurrent 所有自上次调用AcceptChanges后修改过的数据行
ModifiedOriginal 所有自上次调用AcceptChanges后original版本的数据行
New 所有自上次调用AcceptChanges后新添加的行
OriginalRows 返回初始数据行,包含unchanged和deleted 的
Unchanged 所有未更新的数据行
DataView对象还有一些属性,如AllowEdit,AllowDelete和AllowNew,用来得到或设定是否允许更新的值。它们的默认值设为True,允许任何种类的更新。如果在标志设为False时,你想要完成相应的更新操作,会有一个运行时错误发生。
DataTable对象的DefaultView属性用来返回一个DataView对象,作为数据表中内容的默认视图。它按照自然顺序读取数据并显示表中所有的行,而不使用任何过滤。
theMasterGrid.DataSource = m_ds.Tables("Employees").DefaultView
m_ds.Tables("Employees").DefaultView.Sort = "lastname"
theMasterGrid.DataSource = m_ds.Tables("Employees").DefaultView
DataViewManager类是用来存储DataSet中所有表的视图设置。
可以通过传递一个合法的非空的DataSet给类的构造函数来创建DataViewManager
Dim dvm As DataViewManager
dvm = New DataViewManager(m_ds)
Dim dvm As DataViewManager = m_ds.DefaultViewManager
Dim dvm As New DataViewManager()
dvm.DataSet = m_ds
dvs = dvm.DataViewSettings("Employees")
dvs.Sort = "lastname"
theMasterGrid.DataMember = "Employees"
上述例子程序用filter实现了master/detail结构。如果使用.NET中特有的数据绑定控件(如datagrid),能够更好的达到这个目的。在以后的专栏中,我将论述内存中的数据关系,以及它们是如何影响master/detail结构的设计的。
对话:你是否需要控件或组件?
组件是一个特殊的类,它实现了Icomponent接口或派生于实现了Icomponent接口的类。
控件是提供了用户界面功能的组件。在.NET架构中,可以找到两类控件:客户端的Windows Forms 控件和ASP.NET server 控件。
Icomponent接口包含在Idisposable接口中,并提供了一种确定的方法清除资源。
Public Interface IComponent
Inherits IDisposable
.NET组件知道怎样在应用程序域(application domain)中如何串联。这有两种方法:通过引用或通过值,基本功能分别内建于MarshalByRefComponet和MarshalByValueComponent类中。.NET component类,事实上,实现了Idisposable,但直接或间接继承了上述两个类中的一个。
应用程序域是一种轻量级进程。通过引用来列集对象意味着proxy/stub实体对会被创建并处理远程调用。而通过值则意味着该对象的序列化的拷贝传递越过域的边界。
控件是更特殊化的对象,它还提供了用户界面元素。当然,一个控件总是一个component,但反之不一定成立。
有些.NET程序员采取在数据库中建立临时表等方法来解决这类查询问题。而我觉得这种方法不可行,其实只要用.NET类库中提供的DataView类的强大功能(主要是用它的RowFilter属性),就能方便地解决这类查询问题。下面就举一个具体的例子,来说明如何不用SQL语句,用DataView的RowFilter属性来查询。
{
//生成DataTable
System.Data.DataTable myDataTable = new DataTable("本地数据表");
DataColumn myDataColumn;
DataRow myDataRow;
//生成数据列 ID,商品名称,商品价格
myDataColumn = new DataColumn();
myDataColumn.DataType = System.Type.GetType("System.Int32");
myDataColumn.ColumnName = "ID";
myDataColumn.ReadOnly = true;
myDataColumn.Unique = true;
myDataTable.Columns.Add(myDataColumn);
myDataColumn = new DataColumn();
myDataColumn.DataType = System.Type.GetType("System.String");
myDataColumn.ColumnName = "商品名称";
myDataTable.Columns.Add(myDataColumn);
myDataColumn = new DataColumn();
myDataColumn.DataType =System.Type.GetType("System.Decimal");
myDataColumn.ColumnName = "商品价格";
myDataTable.Columns.Add(myDataColumn);
//为数据表添加数据行
myDataRow = myDataTable.NewRow();
myDataRow["id"] = 1;
myDataRow["商品名称"] = "足球";
myDataRow["商品价格"] =57.5;
myDataTable.Rows.Add(myDataRow);
myDataRow = myDataTable.NewRow();
myDataRow["id"] = 2;
myDataRow["商品名称"] = "篮球";
myDataRow["商品价格"] =64.5;
myDataTable.Rows.Add(myDataRow);
myDataRow = myDataTable.NewRow();
myDataRow["id"] = 3;
myDataRow["商品名称"] = "网球";
myDataRow["商品价格"] =6.5;
myDataTable.Rows.Add(myDataRow);
myDataRow = myDataTable.NewRow();
myDataRow["id"] = 4;
myDataRow["商品名称"] = "网球拍";
myDataRow["商品价格"] =388.5;
myDataTable.Rows.Add(myDataRow);
//返回数据表
return myDataTable;
}
步骤二:在aspx前台页面中添加一个DataGrid1,在后台代码的Page_Load中编写如下代码:
if(!this.IsPostBack)
{
Session["Table"]=MakeTable();
DataGrid1.DataSource=(DataTable)Session["Table"];
DataGrid1.DataBind();
}
此时浏览页面,可以看到DataGrid中显示的表中数据。
ID
商品名称
商品价格
1
足球
57.5
2
篮球
64.5
3
网球
6.5
4
网球拍
388.5
步骤三:在aspx前台页面添加一个用来查询Label1,TextBox1和Button1。如下图所示:
步骤四:在查询按钮Button1单击事件中添加如下代码:
DataTable dt=(DataTable)Session["Table"];
//为数据表建立一个数据视图
DataView dv=new DataView(dt);
//用RowFilter属性进行模糊查询
dv.RowFilter="商品名称 LIKE'%"+TextBox1.Text.Trim()+"%'";
DataGrid1.DataSource=dv;
DataGrid1.DataBind();
运行页面后在TextBox1中输入“网”,按查询按钮后 ,DataGrid显示的查询结果如下:
ID
商品名称
商品价格
3
网球
6.5
4
网球拍
388.5
步骤五:在aspx前台页面上添加一个Label2控件,两个TextBox控件-TextBox1和TextBox2,以及一个“查询”按钮,Button2,如下图所示,用来查询用户输入的价格范围中在商品。
步骤六:在后台代码中为Button2按钮单击事件添加如下如下代码:
DataTable dt=(DataTable)Session["Table"];
DataView dv=new DataView(dt);
dv.RowFilter="商品价格>="+TextBox2.Text.Trim()+" AND 商品价格<="+TextBox3.Text.Trim();
DataGrid1.DataSource=dv;
DataGrid1.DataBind();
用户在两个文本框中输入价格范围,10,70后,DataGrid1中显示的查询结果如下:
ID
商品名称
商品价格
1
足球
57.5
2
篮球
64.5
可见,用DataView的RowFilter属性完全能达到SQL语句SELECT语句所实现的功能
RowFilter中的查询语句与SQL语句中SELECT语句的语法和作用都极为相似,以下是摘自MSDN中关于RowFilter查询语句的语法说明:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
用户定义的值可以用在将与列值进行比较的表达式内。字符串值应放在单引号内。日期值应放在磅符号 (#) 内。对于数值,允许使用小数和科学记数法。例如:
"FirstName = 'John'"
"Price <= 50.00"
"Birthdate < #1/31/82#"
对于包含枚举值的列,将值强制转换为整数数据类型。例如:
"EnumColumn = 5"
运算符
使用布尔值 AND、OR 和 NOT 运算符时允许串联。可以使用括号来组合子句和强制优先级。AND 运算符优先于其他运算符。例如:
(LastName = 'Smith' OR LastName = 'Jones') AND FirstName = 'John'
在创建比较表达式时,允许使用下列运算符:
<
>
<=
>=
<>
=
IN
LIKE
在表达式中还支持下列算术运算符:
+(加)
-(减)
*(乘)
/(除)
%(模数)
字符串运算符
若要连接字符串,请使用 + 字符。字符串比较是否区分大小写由 DataSet 类的 CaseSensitive 属性的值来确定。但是,可以用 DataTable 类的 CaseSensitive 属性重写此值。
通配符
在 LIKE 比较中,* 和 % 两者可以互换地作为通配符。如果 LIKE 子句中的字符串包含 * 或 %,那么这些字符应用中括号([])对其进行转义。如果子句中有中括号,那么中括号字符应用中括号对其进行转义(例如 [[] 或 []])。在模式的开头和结尾,或者在模式的结尾,或在模式的开头允许使用通配符。例如:
"ItemName LIKE '*product*'"
"ItemName LIKE '*product'"
"ItemName LIKE 'product*'"
在字符串的中间不允许使用通配符。例如,不允许 'te*xt'。
父/子关系引用
通过在列名称前面加 Parent,就可以在表达式中引用父表。例如,Parent.Price 引用父表的名为 Price 的列。
通过在列名称前面加一个 Child,就可以在表达式中引用子表中的列。但是,因为子关系可以返回多行,所以必须在聚合函数中包括对子列的引用。例如,Sum(Child.Price) 将返回子表中名为 Price 的列的总和。
如果某个表有多个子表,则语法是:Child(RelationName)。例如,如果某个表有两个子表,它们的名称分别为 Customers 和 Orders,则 DataRelation 对象被命名为 Customers2Orders,引用将为:
Avg(Child(Customers2Orders).Quantity)
聚合
支持下列聚合类型:
Sum(求和)
Avg(平均)
Min(最小值)
Max(最大值)
Count(计数)
StDev(统计标准偏差)
Var(统计方差)。
聚合通常沿着关系执行。通过使用上面列出的函数之一和上面“父/子关系引用”中详述的子表列,来创建聚合表达式。例如:
Avg(Child.Price)
Avg(Child(Orders2Details).Price)
聚合也可以在单个表上执行。例如,若要为名为“Price”的列中的数字创建汇总,就用:
Sum(Price)
DataRow[] rows1 = dt.Select( "密码= 'Admins ' ");
DataRow[] rows2 = dt.Select( "密码= 'Admin ' ");
2、定义过滤条件
DataView rowfilter = new DataView(a_ds.Tables[0]);
rowfilter.RowFilter = "密码= 'Admins ' ";
rowfilter.RowStateFilter = DataViewRowState.OriginalRows;
3、将过滤好的数据放在一个 新的 DataTable 中
DataTable dt = rowfilter.ToTable();
如果想放在 DataSet 中处理 :可以定义 DataSet 变量 b_ds
b_ds.Tables.Clear();
b_ds.Tables.Add(dt);
如果想绑定到 datagridview 中显示 可以将 datagridview 的数据源改为 dt
dataGridView.DataSource = dt ;
4、如果想在过滤结果中再过滤 利用 2、中的方法 改 a_ds.Tables[0] 为 dt
5、在过滤中 DataSet 变量 a_ds 的值最好不要改变,每次过滤改变中间变量 dt ,过滤完成后重新绑定dataGridView 的数据源 。
.NET中的视图和过滤器 (DefaultView和RowFilter)的更多相关文章
- django中自定义标签和过滤器
想要实现自定义标签和过滤器需要进行准备工作: 准备(必需)工作: 1 在某个app下创建一个名为templatetags(必需,且包名不可变)的包.假设我们在名为polls的app下创建了一个tem ...
- SpringBoot中拦截器和过滤器的使用
一.拦截器 三种方式 继承WebMvcConfigurerAdapter spring5.0 以弃用,不推荐 实现WebMvcConfigurer 推荐 继承WebMvcConfiguratio ...
- Django内建模版标签和过滤器
第四章列出了许多的常用内建模板标签和过滤器.然而,Django自带了更多的内建模板标签及过滤器.这章附录列出了截止到编写本书时,Django所包含的各个内建模板标签和过滤器,但是,新的标签是会被定期地 ...
- Django框架中的视图和模板
视图views django中的视图就是用来定义函数来处理一些逻辑的核心地方. django中通过urls来建立路径跟views中的视图函数的映射关系. urls中的映射关系 ''' urlpatte ...
- SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系
摘自: http://blog.csdn.net/xiaoyaotan_111/article/details/53817918 一 简介 (1)过滤器: 依赖于servlet容器.在实现上基于函数回 ...
- python 全栈开发,Day70(模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介)
昨日内容回顾 视图函数: request对象 request.path 请求路径 request.GET GET请求数据 QueryDict {} request.POST POST请求数据 Quer ...
- Spring拦截器和过滤器
什么是拦截器 拦截器(Interceptor): 用于在某个方法被访问之前进行拦截,然后在方法执行之前或之后加入某些操作,其实就是AOP的一种实现策略.它通过动态拦截Action调用的对象,允许开发者 ...
- 模板继承and自定义模板标签和过滤器
自定义模板标签和 过滤器: 因为模板标签和过滤器只给我们提供了 这么多 无法对我们的使用造成更多的便利 ,剩下的就需要我们自己去创建新的 模板标签和过滤器了 1.在settings中的INSTALLE ...
- 面试题:struts 拦截器和过滤器
拦截器和过滤器的区别 过滤器是servlet规范中的一部分,任何java web工程都可以使用. 拦截器是struts2框架自己的,只有使用了struts2框架的工程才能用. 过滤器在url-patt ...
随机推荐
- Stanford机器学习---第九讲. 聚类
原文:http://blog.csdn.net/abcjennifer/article/details/7914952 本栏目(Machine learning)包括单参数的线性回归.多参数的线性回归 ...
- 【js】将table的每个td的内容自动赋值给其title属性
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 【VirtualBox】VirtualBox的桥接网络模式,为啥网络不稳定?
网桥模式访问外网非常慢,经常卡死,ping时断时续 七搞八搞,反复重启了几次 TMD 就好了,也不知道什么情况,VirtualBox还是不太好使啊..... 网桥模式 设置 如下: 参考资料: ht ...
- PYTHON实现HTTP基本认证(BASIC AUTHENTICATION)
参考: http://www.voidspace.org.uk/python/articles/authentication.shtml#id20 http://zh.wikipedia.org/wi ...
- 17.把字符串转换成整数[atoi]
[题目] 把字符串转换成整数,需要考虑字符串有效性. [代码] C++ Code 123456789101112131415161718192021222324252627282930313233 ...
- 【读书笔记】读《JavaScript设计模式》之门面模式
一.前言 门面模式,也称Facade(外观)模式.核心的两点作用—— 1> 简化类的接口(让接口变得更加容易理解.容易应用.更加符合对应业务),来掩盖一个非常不同或者复杂的实现 2> 消除 ...
- Android之数据库操作
安卓数据库帮助类 /** * 数据库帮助类,用于管理数据库 * @author Administrator * */ public class PersonSQLiteOpenHelper exten ...
- Codeigniter:如何写一个好的Model
本文是关于在Code Igniter PHP MVC框架中如何编写Model方法. CRUD 方法 CRUD 是Create, Retrieve, Update, and Delete的缩写. 这些是 ...
- Wcf for wp8 使用iis Express 承载Wcf服务部署发布网站(三)
我们接下来要做的是 本地电脑当作服务器(模拟外网服务器)来承载Wcf服务程序,通过引用本地电脑ip地址访问wcf服务程序接口 http://192.168.1.123/Service1.svc 一.先 ...
- UVALive 6885 Flowery Trails 最短路枚举
题目连接: http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=129723 题意: 给你一个n点m图的边 1到n有多条最短路 ...