对于EF的操作,我们已经有了大概的了解了,但对于实战来说,似乎还欠缺着一些常用的功能,那就是批量的删除,更新数据。

承接上面的部分,我们有一个叫做House的数据库,其中包含house表和seller表。

一、使用原生EF如何实现批量删除和修改?

        //批量修改
        public static bool UpdateAllPrice(decimal price)
        {
            bool isOk = false;
            using (HouseEntities db = new HouseEntities())
            {
                var houseList = db.House.ToList();
                //首先获取所有房屋的列表(相当于select * from house,虽然实际会把*替换为所有字段,这样能提升性能)
                houseList.ForEach(x => {
                    x.Price = price;//做一个foreach操作来把每一项的价格改为传入的价格
                    db.Entry(x).State = System.Data.Entity.EntityState.Modified;//把修改后的实体标为已修改
                });
                isOk =  db.SaveChanges() > 0;//若修改数量大于0说明成功
            }
            return isOk;
        }

        //批量删除
        public static bool DeleteHouseByRegion(string region)
        {
            bool isOk = false;
            using (HouseEntities db = new HouseEntities())
            {
                var houseList = db.House.Where(x=>x.Region==region).ToList();
                //首先获取符合条件的房屋的列表
                houseList.ForEach(x =>
                {
                    db.Entry(x).State = System.Data.Entity.EntityState.Deleted;//把修改后的实体标为已删除
                });
                isOk = db.SaveChanges() > 0;//若修改数量大于0说明成功
            }
            return isOk;
        }

由上面的示例代码可以看到。无论是批量删除、修改部分数据,还是所有数据。首先都需要对操作对象进行查询并实例化,再使用遍历方法对其进行修改,删除。

这种方式看起来十分奇怪,以前用SQL,Delete House where region='xxx',或者update house set price=123.123所能实现的功能,现在竟然浪费了这么多的功夫,光是浪费功夫也就算了,EF这种写法在性能上也存在着十分巨大的问题(光是每次查询就够浪费性能的了,更别说维护实例的状态,好在EF会对没有更新的对象撤销UPDATE操作,但感觉还是得不偿失)。

那问题在这里已经很明显了,如何解决它呢?那就要用到entityframework中一个非常好用的扩展“Entityframework.Extended”。这是一个开源的扩展类库,需要.NET 4.0以上的版本才能够支持。你可以在nuget和github上找到它。它使用Lambda表达式树的形式,对对象进行了解析,在解析后直接生成SQL指令来完成数据库操作,相比传统SQL来说,这样做不仅使我们的代码更加优美,在安全性和性能方面,也使我们更加放心。

二、Entityframework.Extended安装

和其他类库一样,安装的时候只要在NUGET上进行搜索就行了,如果搜索不到请尝试添加8.8.8.8来做DNS服务器(实在找不到就等等吧,国外网站经常被墙,哪怕是正常的网站)。

如上图所示即可完成安装(什么?你找不到nuget?好吧,我想我的第一篇文章和VS右上角自带的搜索框能帮助你。

三、使用Entityframework.Extended实现批量删除和修改

        //批量更新
        public static bool UpdateAllPrice(decimal price)
        {
            bool isOk = false;
            using (HouseEntities db = new HouseEntities())
            {
                isOk = db.House.Update(x => new House() { Price = price }) > 0;
                //直接会生成update house set price=xxx的语句并返回受影响行数,这里的X无实际作用,但作为MemberInitExpression,其却是不可缺少的一个部分,这里要注意,不能先new对象再进行对象传输,因为抓取准确字段的时候,我们要用到init表达式,如果对象已经被生成,所有非空字段都将被初始化,这对我们来说,完全不必要。
            }
            return isOk;
        }

        //批量删除
        public static bool DeleteHouseByRegion(string region)
        {
            bool isOk = false;
            using (HouseEntities db = new HouseEntities())
            {
                isOk = db.House.Where(x => x.Region == region).Delete() > 0;//在where后面直接跟Delete就可以实现批量删除了, 是不是很方便?
            }
            return isOk;
        }

上面的代码就是使用extended扩展库之后的写法了,不仅整个代码优美了许多,更实现了更好的性能。在使用扩展库之前,别忘了引用EntityFramework.Extensions命名空间,扩展类是没有SDK自动提醒的。

另外,大家有没有发现?我之前说的,修改,删除,添加操作后一定要savingchanges(),这里没写,是不是错了?当然不是,扩展库直接生成了SQL语句并采用了ADO.NET的方式进行了执行,所以并不需要写savingchanges,在这些扩展方法执行之后就会返回受影响的行数了。