专栏首页技术博客一步一步学Linq to sql(六):探究特性

一步一步学Linq to sql(六):探究特性

延迟执行

IQueryable query = from c in North.Customers select c;

这样的查询句法不会导致语句立即执行,它仅仅是一个描述,对应一个SQL。仅仅在需要使用的时候才会执行语句.比如:

            IQueryable query = from c in North.Customers select c;
            foreach (Customers c in query)
                Response.Write(c.CustomerID);

如果你执行两次foreach操作,将会捕获到两次SQL语句的执行:

            NorthWindDataContext North = new NorthWindDataContext();
            StreamWriter sw = new StreamWriter(Server.MapPath("Log.txt"), true);
            North.Log = sw;
            IQueryable query = from c in North.Customers select c;
            foreach (Customers c in query)
                Response.Write(c.CustomerID);

            foreach (Customers c in query)
                Response.Write(c.ContactName);

            sw.Close();

对应SQL:

对于这样的需求,建议你先使用ToList()等方法把查询结果先进行保存,然后再对集合进行查询:

            IEnumerable<Customers> customers = (from c in North.Customers select c).ToList();
            foreach (Customers c in customers)
                Response.Write(c.CustomerID);
            foreach (Customers c in customers)
                Response.Write(c.ContactName);

那么这样只会捕获到一次SQL语句的执行:

 延迟执行的优点在于我们可以像拼接SQL那样拼接查询句法,然后再执行:

            var query = from c in North.Customers select c;
            var newquery = (from c in query select c).OrderBy(c => c.CustomerID);

DataLoadOptions

            NorthWindDataContext North = new NorthWindDataContext();
            StreamWriter sw = new StreamWriter(Server.MapPath("Log.txt"), true);
            North.Log = sw;
            var products = from p in North.Products select p;
            foreach (var p in products)
            {
                if (p.UnitPrice > 10)
                    ShowDetail(p.Order_Details);
            }
            sw.Close();
        private void ShowDetail(EntitySet<Order_Details> orderdetails)
        {
            foreach (var o in orderdetails)
            {
                Response.Write(o.Quantity + "<br>");
            }
        }

你会发现Linq to sql对每个价格大于10的产品都根据产品号进行了一次查询:

这样的语句查询了N次。这样的查询不是很合理,我们可以通过设置DataContext的DataLoadOption,来指示 DataContext再加载产品信息的同时把对应的产品订单信息一起加载:

            NorthWindDataContext ctx = new NorthWindDataContext();
            StreamWriter sw = new StreamWriter(Server.MapPath("Log.txt"), true);
            ctx.Log = sw;
            DataLoadOptions options = new DataLoadOptions();
            options.LoadWith<Products>(p => p.Order_Details);
            ctx.LoadOptions = options;
            var products = from p in ctx.Products select p;
            foreach (var p in products)
            {
                if (p.UnitPrice > 10)
                    ShowDetail(p.Order_Details);
            }

            sw.Close();

执行上面的查询会发现Linq to sql进行了左连接:

那么,我们怎么限制订单详细表的加载条件那?

加上这句

            options.AssociateWith<Products>(p => p.Order_Details.Where(od => od.Quantity > 80));

这样,就只会有数量大于80的订单详细信息会和产品一起加载。

DataLoadOptions限制

  Linq to sql对DataLoadOptions的使用是有限制的,它只支持1个1对多的关系。一个顾客可能有多个订单,一个订单可能有多个详细订单:     这样的语句执行后会导致查询详细订单的SQL执行N次。而对于多对1的关系,Linq to sql对于DataLoadOptions没有限制。

主键缓存

 Linq to sql对查询过的对象进行缓存,之后的如果只根据主键查询一条记录的话会直接从缓存中读取。比如下面的代码:

            NorthWindDataContext ctx = new NorthWindDataContext();
            StreamWriter sw = new StreamWriter(Server.MapPath("Log.txt"), true);
            ctx.Log = sw;
            Customers c1 = ctx.Customers.Single(customer => customer.CustomerID == "ANATR");
            c1.ContactName = "zhuye";
            Customers c2 = ctx.Customers.Single(customer => customer.CustomerID == "ANATR");
            Response.Write(c2.ContactName);

            sw.Close();

执行后只会产生一条SQL:

由于没有提交修改,所以数据库中的记录还是没有更新。由于这个特性,我们在使用存储过程作为实体更新方法的时候就要当心了,存储过程书写错误,即使你提交了修改也很可能导致缓存中的数据和数据库中的数据不一致,引起不必要的麻烦。

DataContext隔离

 有的时候我们会把对象从外部传入DataContext,要求它更新,由于不同的DataContext是相对独立的。由于新的DataContext中还没有获取实体,我们只能通过附加方式更新数据。

首先把Customer表的主键字段加上IsVersion标识:

            NorthWindDataContext ctx = new NorthWindDataContext();
            StreamWriter sw = new StreamWriter(Server.MapPath("Log.txt"), true);
            ctx.Log = sw;
            Customers c = new Customers { CustomerID = "ALFKI", ContactName = "zhuye", CompanyName = "1111" };
            ctx.Customers.Attach(c, true);
            ctx.SubmitChanges();

            IQueryable query = from o in ctx.Customers
                               where o.CustomerID == "ALFKI"
                               select o;
            foreach (Customers cu in query)
            {
                Response.Write(cu.ContactName);
            }
            sw.Close();

运行如上测试代码,查看结果如下

示例代码下载地址 http://files.cnblogs.com/aehyok/LinqData.zip

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 编写高质量代码改善C#程序的157个建议[匿名类型、Lambda、延迟求值和主动求值]

      从.NET3.0开始,C#开始一直支持一个新特性:匿名类型。匿名类型由var、赋值运算符和一个非空初始值(或以new开头的初始化项)组成。匿名类型有如下基本...

    aehyok
  • Entity Framework 自动生成CodeFirst代码

    在前面的文章中我们提到Entity Framework的“Code First”模式也同样可以基于现有数据库进行开发。今天就让我们一起看一下使用Entity F...

    aehyok
  • MVC项目开发中那些用到的知识点(WCF Rest在MVC项目中的两种调用方式)

     接口的实现还添加[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibility...

    aehyok
  • Flutter实现底部菜单导航

    现在我们的 APP 上面都会在屏幕下方有一排的按钮,点击不同的按钮可以进入不同的界面。就是说在界面的底部会有一排的按钮导航。可看下面的图示。

    砸漏
  • Ubuntu下如何创建XFS文件系统的LVM详解

    lvm(Logical Volume Manager) 逻辑卷管理, 可以满足linux系统动态调整各分区大小,满足服务器在不同的运行时期的需求。

    砸漏
  • 编写高质量代码改善C#程序的157个建议[匿名类型、Lambda、延迟求值和主动求值]

      从.NET3.0开始,C#开始一直支持一个新特性:匿名类型。匿名类型由var、赋值运算符和一个非空初始值(或以new开头的初始化项)组成。匿名类型有如下基本...

    aehyok
  • 继停招中国人后,GitLab加入封禁大军:全面阻止受美国制裁的伊朗等地区开发者账户!

    继去年 11 月份,GitLab 被曝拒绝招聘中国工程师后,这次又陷入封禁伊朗开发者账户的讨论中。

    深度学习与Python
  • (六十四)c#Winform自定义控件-温度计(工业)

    GitHub:https://github.com/kwwwvagaa/NetWinformControl

    冰封一夏
  • 2017 Linux 内核开发报告 Linux统治着计算机世界

    现在是 2017 年,Linux 在统治着计算机世界。不相信?Linux 基金会报告说,Linux 运行着 90% 的公共云工作量,世界上 82% 的智能手机,...

    Debian社区
  • Android module发布管理插件

    最近对发布Android SDK到jcenter的流程有点想法,历经一点点艰辛,做了一款Android Studio插件,希望能够使发布流程更简单友好。

    whp

扫码关注云+社区

领取腾讯云代金券