当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > LINQ学习笔记:投射到X-DOM

ASP.NET
使用函数传递参数来执行相应的数据库操作
如何实现在窗体和窗体之间进行传递数据
ASP.NET中文显示之两种解决方法
ASP.NET、JSP及PHP之间的抉择
ASP.NET 2.0发送电子邮件中存在的问题
谈谈HtmlControl与WebControl的区别与用途
从ASP.NET 1.1升级到ASP.NET 2.0要考虑的Cookie问题
通过系统配置来提高ASP.NET应用程序的稳定性
妙用ASP2.0中的URL映射改变网址
AJAX实现web页面中级联菜单的设计
ASP.NET跨页面传值技巧总结
再议ASP.NET DataGrid控件中的“添加新行”功能
Geometry 对象浅析
重构CollapsibleSplitter
如何利用.NET Framework使用RSS feed
ASP.NET获取IP与MAC地址的方法
在ASP.NET 2.0中使用样式、主题和皮肤
ASP.NET中为GridView添加删除提示框
ASP.NET 2.0,无刷新页面新境界
看看一个.net版对话框控件

ASP.NET 中的 LINQ学习笔记:投射到X-DOM


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 40 ::
收藏到网摘: n/a

投射到X-DOM

我们可以将LINQ查询投射到一个X-DOM. 其数据源可以是LINQ支持的任何一种, 例如:

  • LINQ to SQL 表
  • 本地集合
  • 另外一个X-DOM

不管是那种数据源, 使用LINQ投射一个X-DOM的策略是一样的: 你首先需要编写一个构建表达式用于产生需要的X-DOM形状, 然后围绕这个表达式编写LINQ查询

例如, 假设我们想从一个数据库当中查询客户并产生相应的XML:

 1: <customers>
 2: <customer id="1">
 3: <name>Sue</name>
 4: <buys>3</buys>
 5: </customer>
 6: </customers>

我们开始使用简单的文字为该X-DOM编写一个功能性的构造表达式:

 1: var customers =
 2: new XElement ("customers",
 3: new XElement ("customer", new XAttribute ("id", 1),
 4: new XElement ("name", "Sue"),
 5: new XElement ("buys", 3)
 6: )
 7: );

然后我们将其转换成为一个影射创建LINQ查询:

 1: var customers =
 2: new XElement ("customers",
 3: from c in dataContext.Customers
 4: select
 5: new XElement ("customer",
 6: new XAttribute ("id", c.ID),
 7: new XElement ("name", c.Name),
 8: new XElement ("buys", c.Purchases.Count)
 9: )
 10: );

最后的结果可能类似:

 1: <customers>
 2: <customer id="1">
 3: <name>Tom</firstname>
 4: <buys>3</buys>
 5: </customer>
 6: <customer id="2">
 7: <name>Harry</firstname>
 8: <buys>2</buys>
 9: </customer>
 10: ...
 11: </customers>

在这个例子中外部的查询使得查询从远程的LINQ to SQL转换成了本地的可枚举查询. XElement的构造器并不知道IQueryable<>, 因此它将导致LINQ to SQL立即执行SQL语句.

消灭空元素

假设前面的例子我们还想要包括客户最近的高价值的采购单的信息, 我们可以这样做:

 1: var customers =
 2: new XElement ("customers",
 3: from c in dataContext.Customers
 4: let lastBigBuy = (from p in c.Purchases
 5: where p.Price > 1000
 6: orderby p.Date descending
 7: select p).FirstOrDefault()
 8: select
 9: new XElement ("customer",
 10: new XAttribute ("id", c.ID),
 11: new XElement ("name", c.Name),
 12: new XElement ("buys",c.Purchases.Count),
 13: new XElement ("lastBigBuy",
 14: new XElement("description",
 15: lastBigBuy == null
 16: ? null: lastBigBuy.Description),
 17: new XElement("price",
 18: lastBigBuy == null
 19: ? 0m :lastBigBuy.Price)
 20: )
 21: )
 22: );
 23:

这会去掉空的元素, 也就是那些没有高价值采购单的客户. (如果它是一个本地查询, 而不是LINQ to SQL查询, NullReferenceException异常将会抛出. 在这个例子中, 整个省略lastBigBuy节点会更好. 我们可以通过在条件操作符里面包装一个lastBigBuy的构造器来完成这个目标)

 1: select
 2: new XElement ("customer",
 3: new XAttribute ("id", c.ID),
 4: new XElement ("name", c.Name),
 5: new XElement ("buys", c.Purchases.Count),
 6: lastBigBuy == null ? null :
 7: new XElement ("lastBigBuy",
 8: new XElement ("description",
 9: lastBigBuy.Description),
 10: new XElement ("price", lastBigBuy.Price)

对于那些没有lastBigBuy的客户, null将会被发出而不是XElement. 这也是我们所想要的因为null的内容通常都是被忽略的.

流化一个投射

如果你正在通过调用Save来投射一个X-DOM, 你可以使用XStreamingElement来提高内存的效率. XStreamingElement是一个削减过的XElement版本, 对其子内容使用了延迟加载.要使用它, 你可以简单的使用XStreamingElement来替换外围的XElement:

 1: var customers =
 2: new XStreamingElement ("customers",
 3: from c in dataContext.Customers
 4: select
 5: new XStreamingElement ("customer",
 6: new XAttribute ("id", c.ID),
 7: new XElement ("name", c.Name),
 8: new XElement ("buys", c.Purchases.Count)
 9: )
 10: );
 11: customers.Save ("data.xml");

这个查询将通过XStreamingElement的构造器并且不会被执行直到你在Element上面调用了Save, ToString或者WriteTo; 这避免了一次将整个X-DOM加载到内存当中. 另外一点是该查询还会自动判别是否是重新Save, 你也不能横贯XStreamingElement的子内容——因为它并没有暴露类似Elements或者Attribute的方法.

XStreamingElement是基于XObject的——而不是其他类——因为它有一些有限的成员. 除了Save, ToString和WriteTo之外其他的成员就是:

  • Add方法, 其接受类似构造器的内容
  • Name属性

XStreamingElement不允许按流行的方法读取流的内容——为了达到这个目标, 你必须和X-DOM一起使用XmlReader.

转换X-DOM

我们可以通过重新投影来转换一个X-DOM. 例如, 假设我们想要转换一个msbuild的XML文件到一个简单的格式以便可以用其产生一个报表. 一个mubuild文件看起来类似这样:

 1: <Project DefaultTargets="Build"
 2: xmlns="http://schemas.microsoft.com/dev...>
 3: <PropertyGroup>
 4: <Platform Condition=" '$(Platform)' == '' ">
 5: AnyCPU
 6: </Platform>
 7: <ProductVersion>9.0.11209</ProductVersion>
 8: ...
 9: </PropertyGroup>
 10: <ItemGroup>
 11: <Compile Include="ObjectGraph.cs" />
 12: <Compile Include="Program.cs" />
 13: <Compile Include="Properties\AssemblyInfo.cs" />
 14: <Compile Include="Tests\Aggregation.cs" />
 15: <Compile Include="Tests\Advanced\RecursiveXml.cs" />
 16: </ItemGroup>
 17: <ItemGroup>
 18: ...
 19: </ItemGroup>
 20: ...
 21: </Project>

假设我们只想包含文件, 如下:

 1: <ProjectReport>
 2: <File>ObjectGraph.cs</File>
 3: <File>Program.cs</File>
 4: <File>Properties\AssemblyInfo.cs</File>
 5: <File>Tests\Aggregation.cs</File>
 6: <File>Tests\Advanced\RecursiveXml.cs</File>
 7: </ProjectReport>

以下的查询执行了这个变换:

 1: XElement project = XElement.Load("myProjectFile.csproj");
 2: XNamespace ns = project.Name.Namespace;
 3: var query =
 4: new XElement ("ProjectReport",
 5: from compileItem in
 6: project.Elements (ns + "ItemGroup")
 7: .Elements (ns + "Compile")
 8: let include = compileItem.Attribute ("Include")
 9: where include != null
 10: select new XElement ("File", include.Value)
 11: );

此查询提取了所有的ItemGroup元素, 然后使用Elements的扩展方法去获取一个扁平的包含所有Compile子元素的序列. 注意我们必须要指定一个XML命名空间——原来的文件里面所有的东西都继承了Project元素中定义的命名空间——因此本地元素例如ItemGroup 并不会自动生成一样的命名空间. 我们还提取了Include属性并将其投射到一个元素上面. (全序列完!)