zoukankan      html  css  js  c++  java
  • 一步一步学Entity Framework 4.x (3)

    本系列教程发上去以后,有的朋友问我为什么不用Code First呢?个人认为,各种方法各有千秋,而且不管用哪种模式,最后达到的效果是一样的,实质上使用的基本方法是相通的,这就足够了.况且前面已经全文翻译了一本书,如果重复这本书的内容,就没多大意思了,毫无疑问,本文对于Code First模式的学习也是有指导作用的,理解了基本的机制,再进行其他方面深入知识的掌握就容易了,不是吗?我在这里写的内容都是通过不断的实践摸索总结出来的,可以说是很基础的东西,并不是想要炫耀什么,只是因为前面自已走的弯路太多,不想让像我这种刚入门的人再重复一些不必要的弯路而已...

    书归正传,接上期博客文章,继续将数据查询的问题学习完毕.

    5)单值选择查询:

    在SQL数据查询里,经常会用到SELECT DISTINCT查询,用来搜索数据中的唯一值,注意不是第一个,而是重复数据中的一个.

    比如想要查询Product表中ProductUnit(单位)的个数,就会用到单值选择查询.Linq提供了Distinct扩展方法,解决这一问题,如此例,代码应为:

     var result = from c in ctx.Product
                               select c.ProductUnitId;
                  return result.Distinct().Count();

    而使用方法语法则应为:

    return ctx.Product.Select(c => c.ProductUnitId).Distinct().Count();

    6)多级排序:

    比如按照ProductName排序完成后,还要按ProductUnitName再次进行逆序排序,最后再按ProductBigTypeName来排序,这需要使用下面的查询语法代码(接前述GetProductDepositoryByPrice方法里的代码):

    var result = from c in ctx.Product
                               join d in ctx.ProductSmallType on c.ProductSmallTypeId equals d.ProductSmallTypeId
                               join e in ctx.ProductBigType on d.ProductBigTypeId equals e.ProductBigTypeId
                               join f in ctx.ProductUnit on c.ProductUnitId equals f.ProductUnitId
                               where c.ProductBasePrice<=50 && c.ProductBasePrice >=49
    
                               orderby c.ProductName,f.ProductUnitName descending,e.ProductBigTypeName
                               select new ProductDepository
                               {
                                   ProductName = c.ProductName,
                                   ProductBigTypeName = e.ProductBigTypeName,
                                   ProductSmallTypeName = d.ProductSmallTypeName,
                                   ProductUntName = f.ProductUnitName
    
                               };
                  return result.ToList();

    使用方法语法(按前述GetProductByPrice方法里的代码),则应写作:

    return ctx.Product.Include("ProductUnit").
                      Include("ProductSmallType").Include("ProductSmallType.ProductBigType")
                      .Where(c => (c.ProductBasePrice <= 50 && c.ProductBasePrice >= 49))
                      .OrderBy(c=>c.ProductName )
                      .ThenByDescending(c=>c.ProductUnit.ProductUnitName)
                      .ThenBy(c=>c.ProductSmallType.ProductBigType.ProductBigTypeName)
                      .ToList();

    7)Top 10的实现

    只选择前几条数据可以使用Take方法,比如Take(10)就表示取结果的前10条.可以直接在方法语法后面加上这个扩展方法,各位园友请自行试验,在此不再举例.

    8)实现快速分页的关键方法:Skip方法,这一方法可以跳过指定的记录条数,返回剩余的记录,这可以应用于快速分页,因为跳过的记录不会进入内存,也不会占用服务器资源,这样就可以直接显示指定页面的数据了,Skip方法和Take方法协同使用,可以只调用所需要的当前页面数据,大大缩小的查询数据的区间,分页效率最高.这一方法使用比较简单,就不再举例.

    9)返回结果中第一个匹配给定条件的数据,应该使用First或FirstOrDefault方法,在给定条件有数据返回时.两个方法类似,当给定条件无数据返回时,First方法返回Null,而FirstOrDefault方法返回为默认元素(如果是字符串,返回为"",如果是数字,返回0等等),所以注意对返回结果的处理,特别是对First方法返回值的处理,不要出现引用Null值的错误,否则会引发异常.通常的做法是在使用前对返回值是否为Null进行判断,要么就使用FirstOrDefault方法.

    前面介绍了大部分常用的查询功能,有了这些查询方法,就可以在实际工作中施展拳脚了,大家多尝试多练习,就会体会到Linq查询的妙处.

    6、删除数据

    删除数据有两种情况,一种是对一对多关系中的“多”进行删除,这很容易,直接删除就是,比如Produc表;另一种是对一对多关系中的“一”进行删除,如果没有设置级联删除,将无法直接删除,除非已经将符合条件的“多”的部分全部删除了,才能正常删除与“多”相关的“一”,个人建议开启级联删除功能,这样在实际开发工作中事半功倍,否则在实际运行中出现删除不了的错误,也不好进行调试。在SQL Server Management Stuido里可以很容易地实现级联删除功能,见下图:

    imageimage

    级联设置完成后,就可以方便地进行删除操作了。这时候,我们就不用再顾虑是否能够正确删除的问题了,只要查询到了数据,就可以删除。

    想要删除数据,首先要找到数据,这就要用到前面所学的查询语句及工具了。

    在删除数据时要注意,如果查询得到的是单条数据,例如使用First或FirstOrDefault方法获取的数据,直接调用实体类的DeleteObject方法就可以了,然后再调用SaveChanges方法将所有更改进行更新。但是如果查询得到的是数据集合,就不能像SQL语句那样对数据进行批量删除操作了,这时需要使用foreach循环语句遍历所有数据,逐个调用DeleteObject方法。最后统一调用SaveChanges方法即可(从SaveChanges方法名就可以看到,这个方法是可以批量处理数据的)。

    比如想要删除ProductSmallType表中ProductBigTypeName(需要导航得到,原表中没有这个属性)以9结尾的所有数据,方法如下:

    1)首先在Business文件夹中新建一个类,命名为DeleteData.cs;

    2)在类中添加一个方法DeleteProductSmallTypeByBigTypeName(),代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using ProductEFDemo.Models;
    
    namespace ProductEFDemo.Business
    {
      public static  class DeleteData
        {
          public static void DeleteProductSmallTypeByBigTypeName()
          {
              using (var ctx = new ProductsEntities())
              {
                  var result = ctx.ProductSmallType.Include("ProductBigType")
                             .Where(c => c.ProductBigType.ProductBigTypeName.EndsWith("9"))
                             .ToList();
                  foreach (var productSmallType in result)
                  {
                      ctx.ProductSmallType.DeleteObject(productSmallType);
                  }
                  ctx.SaveChanges();
              }
          }
        }
    }
    

    3)在Presenter文件夹中,添加一个类:DeleteObjectView.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using ProductEFDemo.Business;
    
    namespace ProductEFDemo.Presenter
    {
      public static  class DeleteObjectView
        {
          public static void DeleteProductSmallTypeByBigTypeName()
          {
              Console.WriteLine("真的要全部删除?");
              string str = Console.ReadLine();
              if (str.Substring(0, 1).ToLower() == "y")
              {
                  try
                  {
                      DeleteData.DeleteProductSmallTypeByBigTypeName();
                      Console.WriteLine("成功删除所有相关数据及相关关联数据");
                  }
                  catch (Exception ex)
                  {
    
                      Console.WriteLine(String.Format ("出错,错误信息为:{0}",ex.Message));
                  }
               
    
              }
              
          }
        }
    }
    

    4)在Programm.cs中的Main函数调用这一方法,结果如下:

    image

    再到数据库的ProductSmallType表里去找相关数据,已经没有了,记录已经变成了90条,到Product表里去找相关数据,记录变成了9000条,有1000条数据也被同时删除了,尽管我们并没有显示地指定要删除这些数据,但是由于设置了级联,就将一对多中的多的部分也删除了。

    当然了,这种删除是对数据的永久性删除,一般来说不是一个很好的模式,万一想反悔已经来不及了。所以大型项目通常都是设置一个数据列,标记被删除的那一行数据为已删除(实际上数据还在,只是不在前台里显示了而已),这需要使用更新语句,而不是真正的删除语句,然后以后在确定不会后悔了以后再真的将数据清空,建议园友们在实际项目中也这样操作,算是一味后悔药吧!

    7、更新和修改数据

    这是本系列的最后一部分,实现了添加,查找,删除,下面就该实现数据的修改了。数据修改的方法与数据删除的方法相类似,也是先要通过Linq查询到数据,然后给查询到数据对象的相关属性进行赋值修改,最后再调用SaveChanges方法更新就OK了。

    同样,对于集合类数据的修改,也不能一并进行更新处理,只能通过循环对各个对象逐个进行更新处理。这一点一定要注意!

    下面对ProductUnit表中的ProductName进行修改,将所有“测试”字符串替换为””,步骤如下:

    1)首先还是在Business文件夹中添加一个类:UpdateData.cs:

    2)然后在类中添加一个方法实现前面要实现的更新功能:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using ProductEFDemo.Models;
    
    namespace ProductEFDemo.Business
    {
      public static  class UpdateData
        {
          public static void UpdateProductUnitByUnitName()
          {
              using (var ctx = new ProductsEntities())
              {
                  var result = ctx.ProductUnit.Where(c => c.ProductUnitName.Contains("测试")).ToList();
                  foreach (var productUnit in result)
                  {
                      productUnit.ProductUnitName = productUnit.ProductUnitName.Replace("测试", "");
                  }
                  ctx.SaveChanges();
              }
          }
        }
    }
    

    3)在Presenter文件夹中添加一个类:UpdateDateView.cs。

    4)在类中实现一个方法调用刚刚创建的方法:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using ProductEFDemo.Business;
    
    namespace ProductEFDemo.Presenter
    {
      public static class UpdateDateView
        {
          public static void UpdateProductUnitByUnitName()
          {
             try
             {
                 Console.WriteLine("准备更新数据...");
                 UpdateData.UpdateProductUnitByUnitName();
                 Console.WriteLine("更新成功!");
             }
             catch (System.Exception ex)
             {
                 Console.WriteLine(String.Format("出错,错误信息为:{0}", ex.Message));
             }
             
          }
        }
    }
    

    5)执行程序,结果如下:

    image

    到数据库中检索数据,

    image

    可见数据都进行了更新和修改。是不是很方便?

    总结一下,想怎样改数据都是在实体类的对象上改,对象改完以后直接SaveChanges就OK了,很简单很方便!

    8、小结:Entity Framework还有很多高级知识,如延迟加载(Lazy Load),数据库自定义加载,并发处置等,这些还需要进一步研究和讨论,但是掌握了基础知识以后,这些新的知识就可以获得更好的理解了,希望园友们再接再厉,深入研究EF这一ORM工具,大幅度地提高生产力!

    声明:本文系本人原创,版权归属作者和博客园共同所有,任何组织或个人不得随意转载,修改。需要转载请与本人联系:qouoww@163.com。

  • 相关阅读:
    PS常用美化处理方法大全
    FastReport.Net使用:[32]对话框使用2
    FastReport.Net使用:[31]使用带参查询及存储
    FastReport.Net使用:[30]对话框使用
    FastReport.Net使用:[29]调用存储过程1
    FastReport.Net使用:[28]数据合并
    FastReport.Net使用:[27]样式使用
    FastReport.Net使用:[26]数字格式
    FastReport.Net使用:[25]除数0处理方法
    FastReport.Net使用:[24]其他控件(邮政编码(Zip Code),网格文本(Cellular Text)以及线性刻度尺(Linear Gauge))
  • 原文地址:https://www.cnblogs.com/qouoww/p/2473891.html
Copyright © 2011-2022 走看看