LINQ to Entities多表查询



LINQ技术(即 LINQ to Entities)使开发人员能够通过使用 LINQ 表达式和 LINQ 标准查询运算符,直接从开发环境中针对 实体框架对象上下文创建灵活的强类型查询。LINQ to Entities 查询使用对象服务基础结构。ObjectContext 类是作为 CLR 对象与 实体数据模型 进行交互的主要类。开发人员通过 ObjectContext 构造泛型 ObjectQuery 实例。ObjectQuery 泛型类表示一个查询,此查询返回一个由类型化实体组成的实例或集合。返回的实体对象可供更新并位于对象上下文中。以下是创建和执行 LINQ to Entities 查询的过程:

1.    从 ObjectContext 构造 ObjectQuery 实例。

2.    通过使用 ObjectQuery 实例在 C# 或 Visual Basic 中编写 LINQ to Entities 查询。

3.    将 LINQ 标准查询运算符和表达式将转换为命令目录树。

4.    对数据源执行命令目录树表示形式的查询。执行过程中在数据源上引发的任何异常都将直接向上传递到客户端。

5.    将查询结果返回到客户端。

一、Linq To Entities简单查询

下面将介绍简单的Linq To Entities查询,相关的查询语法可以使用基于表达式或基于方法的语法。本节使用的TestDriver.Net配合Nunit2.4进行测试。

1, 投影

代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Data.Objects;

using NUnit.Framework;

namespace NorthWindModel

{

    [TestFixture]

    public class TestEFModel

    {

        [Test]

        public void Select()

        {

           using (var edm = new NorthwindEntities())

            {

               //基于表达式的查询语法

               ObjectQuery<Customers> customers = edm.Customers;

               IQueryable<Customers> cust1 =from c in customers

                                             select c;

               Assert.Greater(cust1.Count(), 0);

                //使用ObjectQuery类的ToTraceString()方法显示查询SQL语句

               Console.WriteLine(customers.ToTraceString());

 

 

            }

        }

    }

}

输出:

SELECT

[Extent1].[CustomerID] AS [CustomerID],

[Extent1].[CompanyName] AS [CompanyName],

[Extent1].[ContactName] AS [ContactName],

[Extent1].[ContactTitle] AS [ContactTitle],

[Extent1].[Address] AS [Address],

[Extent1].[City] AS [City],

[Extent1].[Region] AS [Region],

[Extent1].[PostalCode] AS [PostalCode],

[Extent1].[Country] AS [Country],

[Extent1].[Phone] AS [Phone],

[Extent1].[Fax] AS [Fax]

FROM [dbo].[Customers] AS [Extent1]

 

1 passed, 0 failed, 0 skipped, took 11.00 seconds (NUnit 2.4).

在上面的输出内容中,可以看到使用了ToTraceString()方法来输出具体的SQL语句。同时Nunit也输出相关的测试情况,请注意查询所花费的时间,以便我们进行查询速度的分析比较。

2, 条件限制

using (var edm =new NorthwindEntities())

{

    //基于表达式的查询语法

    ObjectQuery<Customers> customers = edm.Customers;

    IQueryable<Customers> cust1 = from c in customers

                                 where c.CustomerID == "ALFKI"

                                 select c;

  

    Assert.AreEqual(cust1.Count(), 1);

    foreach (var c in cust1)

        Console.WriteLine("CustomerID={0}", c.CustomerID);

               

    //基于方法的查询语法

    var cust2 = edm.Customers.Where(c => c.CustomerID == "ALFKI");

    Assert.AreEqual(cust2.Count(), 1);

    foreach (var c in cust2)

          Console.WriteLine("CustomerID={0}", c.CustomerID);

 

}

3, 排序和分页

在使用Skip和Take方法实现分页时,必须先对数据进行排序,否则将会抛异常。

using (var edm =new NorthwindEntities())

 {

//基于表达式的查询语法

         ObjectQuery<Customers> customers = edm.Customers;

         IQueryable<Customers> cust10 = (from cin customers

                                        orderby c.CustomerID

                                         select c).Skip(0).Take(10);

 

          Assert.AreEqual(cust10.Count(), 10);

          foreach (var cin cust10)

             Console.WriteLine("CustomerID={0}", c.CustomerID);

   

//基于方法的查询语法

   var cust = edm.Customers.OrderBy(c => c.CustomerID).Skip(0).Take(10);

   Assert.AreEqual(cust.Count(), 10);

   foreach (var c in cust)

       Console.WriteLine("CustomerID={0}", c.CustomerID);

 }

4, 聚合

可使用的聚合运算符有Average、Count、Max、Min 和 Sum。

using (var edm =new NorthwindEntities())

   {

       var maxuprice = edm.Products.Max(p => p.UnitPrice);

       Console.WriteLine(maxuprice.Value);

 }

5, 连接

可以的连接有Join 和 GroupJoin 方法。GroupJoin组联接等效于左外部联接,它返回第一个(左侧)数据源的每个元素(即使其他数据源中没有关联元素)。

using (var edm =new NorthwindEntities())

    {

       var query =from d in edm.Order_Details

                   join order in edm.Orders

                   on d.OrderID equals order.OrderID

                   select new

                    {

                        OrderId = order.OrderID,

                        ProductId = d.ProductID,

                        UnitPrice = d.UnitPrice

                     };

        foreach (var qin query)

         Console.WriteLine("{0},{1},{2}",q.OrderId,q.ProductId,q.UnitPrice);

}

连续条件情况:

                var lst = from c in db.city.Where(t => t.name == cityName)
                          join l in db.city_loc_type
                          on c.city_id equals l.city_id
                          where l.city_loc_code == "0001"
                          select l.city_loc_type_id;

多个join on连接使用

                var lst = (from ui in db.user_info
                           join pr in db.province
                           on ui.province_id equals pr.province_id
                           join ct in db.city
                           on ui.city_id equals ct.city_id
                           select new
                           {
                               userid = ui.user_id,
                               rn = ui.real_name,
                               uc = ui.identity_card,
                               phone = ui.mobile_phone,
                               pid = ui.province_id,
                               pname = pr.name,
                               department = ui.department,
                               addr = ui.home_addr,
                               remark = ui.remark,
                               cityid = ct.city_id,
                               cityName = ct.name,
                           }).ToList();

join on 和where 配合使用

                var rlist = (from r in db.role
                             join rt in db.roletype
                             on r.roletype_id equals rt.roletype_id
                             where list.Contains(r.role_id)
                             select new
                             {
                                 id = r.role_id,
                                 rname = r.role_name,
                                 rtype_id = r.roletype_id,
                                 rtype_name = rt.name,
                                 f = r.role_function,
                                 remark = r.remark,
                             }).ToList();

其他一些方法等就不多说了,和Linq to SQL 基本上是一样的。

二、LINQ to Entities 查询注意事项

l          排序信息丢失

如果在排序操作之后执行了任何其他操作,则不能保证这些附加操作中会保留排序结果。这些操作包括 Select 和 Where 等。另外,采用表达式作为输入参数的First FirstOrDefault 方法不保留顺序。

如下代码:并不能达到反序排序的效果

using (var edm =new NorthwindEntities())

{

     IQueryable<Customers> cc = edm.Customers.OrderByDescending(c => c.CustomerID).Where(c => c.Region !=null).Select(c => c);

     foreach (var c in cc)

         Console.WriteLine(c.CustomerID);

}

l          不支持无符号整数

由于 实体框架不支持无符号整数,因此不支持在 LINQ to Entities 查询中指定无符号整数类型。如果指定无符号整数,则在查询表达式转换过程中会引发NotSupportedException异常,并显示无法创建类型为“结束类型”的常量值。此上下文仅支持基元类型(“例如 Int32、String 和 Guid”)。

如下将会报异常的代码:

using (var edm =new NorthwindEntities())

 {

      uint id = UInt32.Parse("123");

      IQueryable<string> produt = from p in edm.Products

                                 where p.UnitPrice == id

                                  select p.ProductName;

      foreach (string name in produt)

           Console.WriteLine(name);

}

上面的代码中,由于id是uint而不是Int32,String,Guid的标量类型,所以在执行到where p.UnitPrice==id这个地方时,会报异常。

l          不支持引用非标量闭包

不支持在查询中引用非标量闭包(如实体)。在执行这类查询时,会引发 NotSupportedException 异常,并显示消息“无法创建类型为“结束类型”的常量值。此上下文中仅支持基元类型(‘如 Int32、String 和 Guid’)

如下将会报异常的代码:

using (var edm =new NorthwindEntities())

 {

        Customers customer = edm.Customers.FirstOrDefault();

        IQueryable<string> cc = from c in edm.Customers

                                where c == customer

                               select c.ContactName;

         foreach (string name in cc)

              Console.WriteLine(name);

}

上面的代码中,由于customer是引用类型而不是Int32,String,Guid的标量类型,所以在执行到where c==customer这个地方时,会报异常。

好,本节介绍完毕。后面将继续学习EF.
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值