使用LINQ查询关系型数据库

1、概述
LINQ支持自定义提供者,这些提供者将LINQ表达式树转换为数据源所支持的语言,值得关注的是LINQ能够经过IQueryable接口访问ADO.NET对象。
LINQ能够直接对DataSet进行查询,也能够用DataContext和Table(实现了ITable、IQueryable、IEnumerable)。
最基本的工做是定义一个对象关系映射(ORM),用于将C#实体类与数据库中的表映射起来。
为了使用LINQ to SQL,须要一下东西:
1. 引用:System.Data.Linq
2. 一个DataContext实例,用来链接字符串
3. 一个与数据库对应的实体类

2、定义表对象
当咱们为数据库中的表实现一个自定义类(实体类)的时候,就是在定义一个ORM。

【示例:查询全部记录或单条记录或删除指定记录】
using System;
using System.Linq;
using System.Data.Linq;

namespace 简单的ORM和LINQToSQL示例
{
    class Program
    {
        //定义一个私有的链接字符串
        private static readonly string connectionString = "Data Source=.;Initial Catalog=db_Customer;Integrated Security=SSPI;";

        static void Main(string[] args)
        {
            //表示Linq to SQL框架的主入口点,DataContext实例,经过一个链接字符串链接你的数据库
            DataContext customerContext = new DataContext(connectionString);
            //Table:表示基础数据库中特定类型的表。
            //GetTable:返回特定类型的对象的集合,其中类型由 TEntity 参数定义
            Table<Customer> customers = customerContext.GetTable<Customer>();

            var seperator = new string('*', 40);
            Console.WriteLine(seperator);
            //查询全部数据
            var startsWith = from c in customers
                             select c;
            Array.ForEach(startsWith.ToArray(), c => Console.WriteLine(c));
            //Log:获取或设置为目标编写SQL查询或命令
            //Out:获取标准输出流
            //customerContext.Log = Console.Out;
            Console.WriteLine(seperator);
            //查询单条数据(按条件查询)
            var singleInfo = from c in customers
                             where c.CustomerID[c.CustomerID.Length - 1] == '3'
                             select c;
            Array.ForEach(singleInfo.ToArray(), c => Console.WriteLine(c));
            Console.WriteLine(seperator);
            //删除指定的一条数据,根据字段CustomerID='1009'
            var deleteInfo = customers.SingleOrDefault(s => s.CustomerID == "1009");
            //Console.WriteLine(deleteInfo);
            if (deleteInfo == null)
            {
                throw new Exception ("没有该条数据");
            }
            customers.DeleteOnSubmit(deleteInfo);
            customerContext.SubmitChanges();
            Console.ReadKey();
        }
    }
}
【增长、编辑一条记录】
using System;
using System.Linq;
using System.Data.Linq;
using 简单的ORM和LINQToSQL示例;
using System.Collections.Generic;

namespace 增长修改记录
{
    class Program
    {
        private static readonly string connectionString = "Data Source=.;Initial Catalog=db_Customer;Integrated Security=SSPI;";
        static void Main(string[] args)
        {
            DataContext context = new DataContext(connectionString);
            Table<Customer> customers = context.GetTable<Customer>();
            var seperator = new string('*', 40);
            //插入一条记录
            Customer c = new Customer
            {
                CustomerID = "201",
                ContactName = "徐帅",
                Phone = "12122121121",
                CompanyName="妈蛋的哈哈哈"
            };
            customers.InsertOnSubmit(c);
            //插入多条数据
            var cc = new List<Customer>
            {
                new Customer {CustomerID="202",ContactName="大胖", Phone="32323232323",CompanyName="公司名" },
                new Customer {CustomerID="003",ContactName="fsfds", Phone="656765768",CompanyName="公司的名字" },
                new Customer {CustomerID="004",ContactName="艰苦艰苦", Phone="0897876565",CompanyName="公司的haoming" }
            };
            customers.InsertAllOnSubmit(cc);
            //修改一条记录
            var editInfo = customers.SingleOrDefault<Customer>(s => s.CustomerID =="1001");
            editInfo.ContactName = "修改秀嘎";
            context.SubmitChanges();
            Console.ReadKey();
        }
    }
}
映射到数据库表的类叫实体类。对LINQ而言,实体都要用TableAttribute和ColumnAttribute进行修饰。
 ColumnAttribute能够应用在任何字段或属性上(public、private、internal),不过当LINQ把修改保存回数据库时,实体中只有那些带有ColumnAttribute的元素才会被持久化。
ColumnAttribute的命名参数
命名属性描述备注AutoSync指示什么时候将该列与数据库进行同步好比:AutoSync.OnInsertCanBeNull指示该列是否能够包含null值 DbType表示DbType枚举值之一 Expression说明计算列是如何产生的 IsDbGenerated指示该列是不是自动生成的好比自动生成的主键列(数据库中用IDENTITY)IsDiscriminator指示该列是否包含LINQ TO SQL继承层次结构的鉴别器值 IsPrimaryKey指示该列是不是主键 IsVersion指示该列是不是数据库时间戳或版本号 Name显示列名称 Storage标识当前实体类中用于存储该列的值的字段 UpdateCheck指示如何检测并发冲突 
【示例】
[Column(IsPrimaryKey =true,Name = "CustomerID",Storage ="customerid",CanBeNull =false,DbType ="varchar(20)")]
        public string CustomerID { get; set; }

3、查看由LINQ生成的查询文本html

【示例】
/表示Linq to SQL框架的主入口点,DataContext实例,经过一个链接字符串链接你的数据库
            DataContext customerContext = new DataContext(connectionString);
            //Table:表示基础数据库中特定类型的表。
            //GetTable:返回特定类型的对象的集合,其中类型由 TEntity 参数定义
            Table<Customer> customers = customerContext.GetTable<Customer>();

            Console.WriteLine("SELECT:{0}", customerContext.GetCommand(customers).CommandText);
【结果】
SELECT:SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax]
FROM [tb_Customer] AS [t0]
以上咱们都是直接使用DataContext类的,固然咱们也能够直接继承DataContext,并在新类中嵌入诸如链接字符串之类的一些信息,这会让LINQ to SQL变得更加容易使用。
DataContext是LINQ to SQL的起点。一个DataContext实例表明的是针对一组相关操做的一个“工做单元”。DataContext是一个轻量级的类,经常用于方法范围级别,而不是建立一个DataContext实例并重复使用。
如下,我定义了一个newDataContext类,用于继承DataContext类,并嵌入了链接字符串。
【示例】
using System;
using System.Linq;
using 查看由LINQ生成的查询文本;
using System.Data.Linq;

namespace 经过DataContext对象联接关系型数据
{
    class Program
    {
        static void Main(string[] args)
        {
            newDataContext context = new newDataContext();
            Table<OrderDetail> details = context.GetTable<OrderDetail>();
            //查看SQL文本
            Console.WriteLine("Select:{0}", context.GetCommand(details).CommandText);
            Console.WriteLine();

            var result = from detail in details
                         where detail.OrderID == "1005"
                         select detail;
            Array.ForEach(result.ToArray(), r => Console.WriteLine(r));
            Console.ReadKey();
        }
    }
    public class newDataContext : DataContext
    {
        private static readonly string connectionString = "Data Source=.;Initial Catalog=db_Customer;Integrated Security=true";
        public newDataContext() : base(connectionString)
        {
        }
    }
}
4、查询数据集 
       LINQ to DataSet的目的并非取代ADO.NET,实际上,LINQ to DataSet代码是创建在ADO.NET代码之上的,而且与之协同工做。学过ADO.NET的都知道,当数据提供程序不一样时,所采起的类也有些许差别(尽管步骤是同样的,思想是同样的),值得注意的是,当数据来自多个数据提供者(或执行本地查询,或生成报表和分析)时,LINQ to DataSet将更有用。
那么,LINQ对DataSet的支持主要是经过哪两个类呢?
linq对DataSet的支持
类名 扩展方法      备注
DataRowExtensions Field   SetField 行扩展方法提供对数据的字段级访问
DataTableExtensions AsDataView  AsEnumerable  CopyToDataTable 表扩展方法将会产生一个可查询的序列
【示例】
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.SqlClient;

namespace 从DataTable中获取数据
{
    class Program
    {
        private static readonly string connectionString = "Data Source=.;Initial Catalog=db_Customer;Integrated Security=true";

        static void Main(string[] args)
        {
            //建立一个存储数据的容器“内存”
            DataSet data = new DataSet();
            using(SqlConnection con=new SqlConnection(connectionString))
            {
                con.Open();
                string selectSQL = "select * from tb_OrderDetail";
                SqlCommand com = new SqlCommand(selectSQL, con);
                //查询数据
                SqlDataAdapter adapter = new SqlDataAdapter(com);
                //将查询到的数据以表的形式放到data中
                adapter.Fill(data, "OrderDetails");
            }
            //定义一个数据表并找到容器中的表
            DataTable orderDetailTable = data.Tables["OrderDetails"];
            //对该表进行查询、筛选、排序 ,使用了ADO.NET和一个LINQ to DataSet查询
            //而这个查询则使用了AsEnumerable扩展方法
            IEnumerable<DataRow> orderDetails = from orderDetail in orderDetailTable.AsEnumerable()
                                                where orderDetail.Field<double?>("discount")> 0.8
                                                orderby orderDetail.Field<double>("discount")
                                                select orderDetail;

            Console.WriteLine("OrderDetai Information :");
            foreach (DataRow row in orderDetails.Take(3))
            {
                Console.WriteLine("订单号:"+row.Field<string>("orderid"));
                Console.WriteLine("产品编号:"+row.Field<string>("productid"));
                Console.WriteLine("价格:"+row.Field<decimal>("unitprice"));
                Console.WriteLine("销售总数:"+row.Field<int>("quantity"));
                Console.WriteLine("折扣率:"+row.Field<double>("discount")==null?0: row.Field<double>("discount"));
                Console.WriteLine(Environment.NewLine);
            }
            Console.ReadKey();
        }
    }
}

5、在DataSet上定义联接
using System;
using System.Linq;
using System.Data;
using System.Data.SqlClient;

namespace 在DataSet上定义联接
{
    class Program
    {
        private static readonly string connectionString = "Data Source=.;Initial Catalog=db_Customer;Integrated Security=true";

        static void Main(string[] args)
        {
            //一次性调用多个SQL语句
            const string selectSQL = "select * from tb_OrderDetail;select * from tb_Order;";

            DataSet data = new DataSet();
            using(SqlConnection con=new SqlConnection(connectionString))
            {
                con.Open();
                SqlCommand com = new SqlCommand(selectSQL, con);
                com.CommandType = CommandType.Text;
                SqlDataAdapter adapter = new SqlDataAdapter(com);
                adapter.Fill(data);
            }

            DataTable orders = data.Tables[0];
            DataTable orderDetails = data.Tables[1];

            var orderResults = from order in orders.AsEnumerable()
                               join detail in orderDetails.AsEnumerable()
                               on order.Field<string>("orderid") equals detail.Field<string>("orderid")
                               orderby order.Field<double?>("discount")
                               select new
                               {
                                   OrderID = detail.Field<string>("orderid"),
                                   ProductID = detail.Field<string>("productid"),
                                   UnitPrice = order.Field<decimal?>("unitprice"),
                                   Quantity = order.Field<int?>("quantity"),
                                   Discount = order.Field<double?>("discount")
                               };

            Console.WriteLine("Orders & Details");
            foreach (var item in orderResults)
            {
                Console.WriteLine("Order ID:{0}", item.OrderID);
                Console.WriteLine("Product ID:{0}", item.ProductID);
                Console.WriteLine("Unitprice:{0}", item.UnitPrice);
                Console.WriteLine("Quantity:{0}", item.Quantity);
                Console.WriteLine("Discount:{0}", item.Discount);
                Console.WriteLine();
            }
            Console.ReadKey();
        }
    }
}

6、使用LINQ to DataSet进行数据绑定
    数据绑定的关键是IEnumerable,数据绑定是先经过IEnumerable和反射来读取公共属性的名称,而后将这些属性及其值绑定到控件,如GridView。
     可绑定性也能够经过实现了IBindgList的类来提供。IBindgList自己就实现了IEnumerable接口。因为Linq序列返回的是IEnumerable<T>对象,所以它们自己是可绑定的。EntitySet是可用于实体的属性,它自己就表示着一种映射关系。EntitySet也实现了IEnumerable,所以它也是可绑定的。

     实现方式很简单,即经过linq语句查询数据库,获得的结果为数据源,而后进行绑定数据库