LINQ To DataSet 2

本文详细介绍了LINQtoDataSet的核心概念,包括如何通过DataTableExtensions和DataRowExtensions扩展方法实现DataTable、DataView和IEnumerable之间的转换,以及如何在LINQ查询中应用这些转换。重点讨论了在进行数据行集合操作时使用DatarowComparer.Default的重要性,以及SetField方法如何灵活地设置或获取数据行字段值,同时提供了实际示例来说明这些概念的应用。

 

LINQ to DataSet主要是提供对离线数据的支持,只有在填充DataSet之后,我们才能使用LINQ to DataSet来查询数据。其功能主要是通过System.Data.DataRowExtions和System.Data.DataTableExtensions两个静态类中的扩展方法来公开的。LINQ to DataSet是LINQ to ADO.Net中的一部分,但这部分所占比重非常小,内容也比较少。下面就让我们首先来看看DataTableExtensions中的扩展方法:

public   static  EnumerableRowCollection < DataRow >  AsEnumerable( this  DataTable source)
----------------------------------------------------------------------------------------------------
public   static  DataView AsDataView( this  DataTable table)
public   static  DataView AsDataView < T > ( this  EnumerableRowCollection < T >  source)  where  T : DataRow
-----------------------------------------------------------------
public   static  DataTable CopyToDataTable < T > ( this  IEnumerable < T >  source)  where  T : DataRow
public   static   void  CopyToDataTable < T > ( this  IEnumerable < T >  source,DataTable table,LoadOption options)  where  T : DataRow
public   static   void  CopyToDataTable < T > ( this  IEnumerable < T >  source,DataTable table,LoadOption options,FillErrorEventHandler errorHandler)  where  T : DataRow

从定义中就可以看出这三类主要是提供DataTable、DataView和IEnumerable三者之间的转换。大家都知道LINQ to Object查询主要是对IEnumerable序列进行的操作,这样就使得DataTable、DataView和LINQ之间建立了一个转换桥梁。

因此,在我们需要将DataTable应用于LINQ to DataSet查询是要先调用AsEnumerable完成DataTable到LINQ的转换。如果我们需要将LINQ to DataSet的查询的结果进行数据绑定时我们需要调用AsDataView的泛型版来完成LINQ到DataView的转换。当然我们也可以使用CopyToDataTable来进行LINQ到DataTable的转换。

注意:如果在我们完成了DataTable到LINQ(IEnumerable)的转换之后(也就是调用AsEnumerable扩展方法),需要进行两个DataRow序列的集合操作如Distinct,Union,Except,Intersect,SequenceEqual,这些操作都需要对数据源中的元素进行相等比较,由于缺省情况下都是调用数据源中的元素的GetHashCode和Equals操作来判断的,对于DataRow而言就是判断对象的引用是否相等,这样可能会导致我们不期望的结果(DataRow里面的数据内容是相同的,但不是同一个对象),所以我们要使用Distinct,Union,Except,Intersect,SequenceEqual带IEqualityComparer的重载版本,使用System.Data.DataRowComparer.Default作为参数。这个比较器类是.Net3.5专门为LINQ to DataSet新增加的,用于比较DataRow的值的,它是通过先比较DataColumn的数量,然后使用该列中类型的Equals方法进行比较。

不带LoadOptions参数的CopyToDataTable方法将自动为每一行的每一个字段创建(更新)原始版本和当前版本,带有LoadOptions参数的CopyToDataTable重载版本可以让你指定是创建(更新)原始版本或是当前版本,或者两者都填充。LoadOptions选项有下面三个选项值可以选择:

OverwriteChanges: 创建(更新)每一列的当前值和原始值

PreserveChanges: 创建(更新)每一列的原始值

Upset: 创建(更新)每一列的当前值

接下来,让我们来看看DataRowExtensions中的扩展方法。在这个DataRowExtensions中的扩展方法主要是从数据行中获得字段的值(泛型的Field方法)和设置数据行中字段的值(泛型的SetField方法)。

public static T Field<T>(this DataRow row,DataColumn column)
public static T Field<T>(this DataRow row,int columnIndex)
public static T Field<T>(this DataRow row,string columnName)
public static T Field<T>(this DataRow row,DataColumn column,DataRowVersion version)
public static T Field<T>(this DataRow row,int columnIndex,DataRowVersion version)
public static T Field<T>(this DataRow row,string columnName,DataRowVersion version)
public static void SetField<T>(this DataRow row,DataColumn column,T value)
public static void SetField<T>(this DataRow row,int columnIndex, T value)
public static void SetField<T>(this DataRow row,string columnName,T value)

其中,row: 是我们要使用的数据行对象实例

column: 指定要返回(设置)其值的列

columnIndex: 指定要返回(设置)其值的列的索引

columnName: 指定要返回(设置)其值的列名

value: 要设置的新值,如果是null,将自动转换为DBNull.Value

version: 要获取的数据行的版本

下面,我们就来看看一个使用LINQ to DataSet的实例,这个例子主要描述了一下上面扩展方法的用法,同时给出了部分注意的事项:

public static class LINQToDataSet
{
    
public class Student
    
{
        
public int Id;
        
public string Name;
    }

    
public static DataTable GetDataTable(Student[] students)
    
{
        DataTable table 
= new DataTable();
        table.Columns.Add(
"Id"typeof(Int32));
        table.Columns.Add(
"Name"typeof(string));
        
foreach (Student student in students)
        
{
            table.Rows.Add(student.Id, student.Name);
        }

        
return (table);
    }

    
public static void PrintStudentTable(DataTable dt)
    
{
        PrintStudentTable(dt.AsEnumerable());
    }

    
public static void PrintStudentTable(IEnumerable<DataRow> dt)
    
{
        Console.WriteLine(
"================================================================");
        
try
        
{
            
foreach (DataRow dataRow in dt.AsEnumerable())
            
{
                Console.WriteLine(
"Student Id = {0} :original {1}:current {2}",
dataRow.Field
<int>("Id"),
dataRow.Field
<string>("Name", DataRowVersion.Original),
dataRow.Field
<string>("Name", DataRowVersion.Current));
            }

        }

        
catch (Exception e)
        
{
            Console.WriteLine(
"Exception:" + e.Message);
        }

        Console.WriteLine(
"================================================================");
    }

    
public static void Test()
    
{
        Student[] students 
= new Student { Id = 1, Name = "Lazy Bee" },
                               
new Student { Id = 7, Name = "Flying Wind" },
                               
new Student { Id = 13, Name = "PiPi Zhu" },
                               
new Student { Id = 72, Name = "Chong Chong" }}
;
        DataTable originalTable 
= GetDataTable(students);
        
//我们试图访问DataTable中数据行的Orginal版本,由于此时还没有建立原始版本,
        
//所以将导致异常
        Console.WriteLine("We try to get access to original version, so we will get the exception.:");
        PrintStudentTable(originalTable);
        
//我们使用CopyToDataTable来建立DataTable中数据行的Orginal版本
        Console.WriteLine("We will use CopyToDataTable to build original version.");
        DataTable newTable 
= originalTable.AsEnumerable().CopyToDataTable();
        PrintStudentTable(newTable);
        
//使用SetField来更新
        Console.WriteLine("After call SetField to change name.");
        (from s 
in newTable.AsEnumerable()
         
where s.Field<string>("Name"== "PiPi Zhu"
         select s).Single
<DataRow>().SetField("Name""George Oscar Bluth");
        PrintStudentTable(newTable);
        
//使用SetField来设置null
        Console.WriteLine("After call SetField to change name to null.");
        (from s 
in newTable.AsEnumerable()
         
where s.Field<int>("Id"== 13
         select s).Single
<DataRow>().SetField<string>("Name"null);
        PrintStudentTable(newTable);
        
//使用CopyToDataTable来合并,由于我们没有指定表的主键,
        
//所以只会简单的追加在目标数据表的最后
        Console.WriteLine("After call CopyToDataTable.We will not get our expected result because we have not set primary key.");
        
//首先,我们调用AcceptChanges来建立Original版本,否则,避免显示时抛出异常
        originalTable.AcceptChanges();
       newTable.AsEnumerable().CopyToDataTable(originalTable, LoadOption.OverwriteChanges);
        PrintStudentTable(originalTable);
        
//我们使用Distinct来去掉刚才重复的记录,由于此时我们没有使用DatarowComparer.Default
        
//所以我们将得不到我们想要的结果
        Console.WriteLine("After call Distinct.We will not get our expected result because we have not used DatarowComparer.Default comparer.");
        IEnumerable
<DataRow> distinctTable=originalTable.AsEnumerable().Distinct();
        PrintStudentTable(distinctTable);
        
//我们使用Distinct来去掉刚才重复的记录,使用DatarowComparer.Default比较器
        
//所以我们将得到我们想要的结果
        Console.WriteLine("After call Distinct.this is what we want.");
       distinctTable
=originalTable.AsEnumerable().Distinct(DataRowComparer.Default);
        PrintStudentTable(distinctTable);
        
//我们先设置主键,然后再使用CopyToDataTable来合并
        Console.WriteLine("After call CopyToDataTable.this is what we want.");
        originalTable 
= GetDataTable(students);
        originalTable.PrimaryKey 
= new DataColumn[] { originalTable.Columns["Id"] }
        newTable.AsEnumerable().CopyToDataTable(originalTable, LoadOption.OverwriteChanges);
        PrintStudentTable(originalTable);     
    }

}


例子中有比较详尽的注释,相信大家看应该没有什么问题。

这个例子的输出结果为:

We try to get access to original version, so we will get  the exception.:
================================================================

Exception:There 
is  no Original data to access.
================================================================

We will use CopyToDataTable to build original version.
================================================================
Student Id 
= 1  :original Lazy Bee:current Lazy Bee
Student Id 
= 7
 :original Flying Wind:current Flying Wind
Student Id 
= 13
 :original PiPi Zhu:current PiPi Zhu
Student Id 
= 72
 :original Chong Chong:current Chong Chong
================================================================

After call SetField to change name.
================================================================
Student Id 
= 1  :original Lazy Bee:current Lazy Bee
Student Id 
= 7
 :original Flying Wind:current Flying Wind
Student Id 
= 13
 :original PiPi Zhu:current George Oscar Bluth
Student Id 
= 72
 :original Chong Chong:current Chong Chong
================================================================

After call SetField to change name to 
null .
================================================================

Student Id 
= 1  :original Lazy Bee:current Lazy Bee
Student Id 
= 7
 :original Flying Wind:current Flying Wind
Student Id 
= 13
 :original PiPi Zhu:current
Student Id 
= 72
 :original Chong Chong:current Chong Chong
================================================================

After call CopyToDataTable.We will not 
get our expected result because we have not set  primary key.
================================================================

Student Id 
= 1  :original Lazy Bee:current Lazy Bee
Student Id 
= 7
 :original Flying Wind:current Flying Wind
Student Id 
= 13
 :original PiPi Zhu:current PiPi Zhu
Student Id 
= 72
 :original Chong Chong:current Chong Chong
Student Id 
= 1
 :original Lazy Bee:current Lazy Bee
Student Id 
= 7
 :original Flying Wind:current Flying Wind
Student Id 
= 13
 :original :current
Student Id 
= 72
 :original Chong Chong:current Chong Chong
================================================================

After call Distinct.We will not 
get  our expected result because we have not used DatarowComparer.Default comparer.
================================================================

Student Id 
= 1  :original Lazy Bee:current Lazy Bee
Student Id 
= 7
 :original Flying Wind:current Flying Wind
Student Id 
= 13
 :original PiPi Zhu:current PiPi Zhu
Student Id 
= 72
 :original Chong Chong:current Chong Chong
Student Id 
= 1
 :original Lazy Bee:current Lazy Bee
Student Id 
= 7
 :original Flying Wind:current Flying Wind
Student Id 
= 13
 :original :current
Student Id 
= 72
 :original Chong Chong:current Chong Chong
================================================================

After call Distinct.
this is  what we want.
================================================================

Student Id 
= 1  :original Lazy Bee:current Lazy Bee
Student Id 
= 7
 :original Flying Wind:current Flying Wind
Student Id 
= 13
 :original PiPi Zhu:current PiPi Zhu
Student Id 
= 72
 :original Chong Chong:current Chong Chong
Student Id 
= 13
 :original :current
================================================================

After call CopyToDataTable.
this is  what we want.
================================================================

Student Id 
= 1  :original Lazy Bee:current Lazy Bee
Student Id 
= 7
 :original Flying Wind:current Flying Wind
Student Id 
= 13
 :original :current
Student Id 
= 72
 :original Chong Chong:current Chong Chong
================================================================

总结,在使用LINQ to DataSet的时候需要注意以下几个方面:

1、 在对IEnumeralbe进行数据行的集合操作如Distinct, Except, Union, Intersect, SequenceEqual时,需要使用System.Data.DatarowComparer.Default作为比较器作为输入参数,以保证对DataRow是进行值比较,而不是引用比较。当然,如果GroupBy或者其他操作的key的类型是DataRow时,也需要使用此比较器,以使我们得到我们期望的行为。

2 、SetField可以将字段值设置为null,并且SetField方法将自动将其转换为DBNull.Value.

3 、Field可以完成从DBNull.Value到null的转换。也就是说,如果该字段的值是DBNull.Value 时,Field方法将自动将其转为null并返回。这个方法是强类型的,不需要象通过列名或者列索引返回字段值一样将Object类型进行造型成需要的类型(值类型进行拆箱操作),(如果字段的值是DBNull.Value时进行造型还将导致抛出异常)Field扩展方法自动做了这些处理,省去了开发人员手动进行这些处理的麻烦。

4 、缺省情况下,数据行的Original版本中是没有值的,试图访问时将导致异常发生。当然,可以在访问之前使用DataRow.HasVersion来进行判断,以防止异常的发生。也可以通过调用DataRow.AcceptChanges方法来建立Original版本来避免异常的发生。不带LoadOptions参数的CopyToDataTable扩展方法也会为返回的DataTable自动建立DataRow的Original和Current版本.

5 当使用带LoadOptions输入参数的CopyToDataTable扩展方法时,必须为目标DataTable指定主键列,否则,该函数只是将源DataTable追加到目标DataTable的最后面。可能达不到期望更新的结果

转自 http://kb.cnblogs.com/page/42584/3/
内容概要:本文系统介绍了算术优化算法(AOA)的基本原理、核心思想及Python实现方法,并通过图像分割的实际案例展示了其应用价值。AOA是一种基于种群的元启发式算法,其核心思想来源于四则运算,利用乘除运算进行全局勘探,加减运算进行局部开发,通过数学优化器加速函数(MOA)和数学优化概率(MOP)动态控制搜索过程,在全局探索与局部开发之间实现平衡。文章详细解析了算法的初始化、勘探与开发阶段的更新策略,并提供了完整的Python代码实现,结合Rastrigin函数进行测试验证。进一步地,以Flask框架搭建前后端分离系统,将AOA应用于图像分割任务,展示了其在实际工程中的可行性与高效性。最后,通过收敛速度、寻优精度等指标评估算法性能,并提出自适应参数调整、模型优化和并行计算等改进策略。; 适合人群:具备一定Python编程基础和优化算法基础知识的高校学生、科研人员及工程技术人员,尤其适合从事人工智能、图像处理、智能优化等领域的从业者;; 使用场景及目标:①理解元启发式算法的设计思想与实现机制;②掌握AOA在函数优化、图像分割等实际问题中的建模与求解方法;③学习如何将优化算法集成到Web系统中实现工程化应用;④为算法性能评估与改进提供实践参考; 阅读建议:建议读者结合代码逐行调试,深入理解算法流程中MOA与MOP的作用机制,尝试在不同测试函数上运行算法以观察性能差异,并可进一步扩展图像分割模块,引入更复杂的预处理或后处理技术以提升分割效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值