NewLife.XCode 上手指南(四) 级联操作
一、本节简介
上一节我们讲的是扩展属性,说白了就是从Subject中点出Teacher,从Teacher中可以点出Subject的List. 通常在实际应用中,我们删除了Teacher,那么这个老师所带的课程也就没有用了,因为Subjcet没有任课老师了.所以我们希望,在删除Teacher的时候同时一起删除的还有那些课程.所以就有了级联操作.
二、逻辑关系
在演示级联操作之前,我们先理一下关系,一个课程对应了一个老师,而一个老师可以带多个课目, 这样一来删除老师的时候可以把其下的所有课目给删掉,但是删科目的时候,不可以删除老师,因为其他科目还关联着这个老师.逻辑关系理清了,然后我们来介绍XCode中的级联操作.
三、关于Delete和OnDelete以及其他的一些说明
XCode中我们可以通过重载OnDelete,Delete,OnUpdate,Update这些方法.
我们来看看Delete方法吧.在Delete方法进行验证过后调用了OnDelete方法,也就是说OnDelete方法才是正真的数据库删除操作.
同时,我们看到了Delete的说明,如果实体没有完整信息,那么就无法通过扩展属性删除附属数据.
这个是什么意思呢? 解释一下,通常我们可能碰到这样的情况,在一个列表中,点击某一列后面的删除按钮,这个时候我们都是通过Post参数的方式来获取到需要删除的那行数据的主键ID,在程序里我们可能会这么写
string strid = Request.QueryString["id"]; int id = -1; if (!int.TryParse(strid, out id)) throw new Exception("非法参数!"); //第一种方法直接用实体静态方法删除 Domain.Teacher.Delete(new string[] {Domain.Teacher._.ID}, new object[] {id}); //第二种方法new一个实体删除
Domain.Teacher teacher = new Domain.Teacher() {ID = id};
teacher.Delete();
//第二种方法先查询,后删除 Domain.Teacher.FindByID(id).Delete();
那么三种方法有什么区别?
首先第一种,是不推荐这么写的,这样写呢就相当于你组了一条SQL, Delete From teacher where id = 1; XCode由于没有获取到实体什么都帮不了你,更重要的是,XCode不会帮你删除和更新Cache中的内容,也就是说直到下一次Cache过期前,你删除的那条数据,还是存在中Cache,如果别人在查询的时候就会命中Cache,造成数据的不统一;
第二种方法,这种方法仅适用于ID为自增主键的情况,XCode会自动帮你尝试级联删除,但是不能保证所有的级联都能删除掉,原因我们在后面的举例.这里提一下,因为实体除了ID其他所有的属性都是null;
第三种方法是最推荐的方法,首先对于一个曾经有性能洁癖的人来说,我是不喜欢查询后删除的,但是这里大石头告诉我,这种查询不会超过20ms,这是主键查询啊! 主键查询是最快的了.没有什么能比主键查询还快的了,所以这个性能的损耗可以忽略不记,但是带来的优势却是级联操作的完整性和Cache的操作的完整性.
四、XCode中如何写级联操作
首先我们已经知道重载OnDelete,OnUpdate即可.所以操作起来很简单.而且本节我们不用给XCode编写任何代码,XCode代码生成器已经帮我们做好了,各位看官可以打开Teacher.Biz.cs第54行可以看到已经重载了OnDelete了
protected override int OnDelete() { if (Subjects != null) Subjects.Delete(); return base.OnDelete(); }
这里对代码做一些解说,同时也是对上面第二种方法的进一步说明,为什么级联操作会不完整.同时也是对上一节扩展属性的进一步巩固.if(Subjects != null)
这里的Subjects就是上一节我们说的扩展属性,程序是死的,程序是没有思想的,所以他会去找到这个Subject属性,然后进入get方法,判断发现_Subject确实是null 而且id>0并且字典里也是不存在相应数据,所以就会去执行FindAllByTeacherID的方法来填充这个Subjects,到这个Get结束,我们的teacher这个new出来的对象除了id和subjects两个属性不是null外 其他属性仍然是null,不要以为XCode会智能的帮你把其他属性给自动获取,这个Subjets正好是你get方法写的巧合,是靠ID来查找的.
举个例子,如果Teacher类中有一个属性是OfficeID,这个OfficeID又关联到另一张表Office,也就是说多个教师在一个办公室中,还可以查某个办公室有哪些老师,这个时候,由于你是new的一个teacher实体,并且除了id外其他都是null
所以即使你写了一个Office的扩展属性,跑到Get方法里执行到_Office = Office.FindAllByOfficeID(OfficeID); 这个地方的OfficeID是null,要么报错,要么就是查不到.总之你的级联操作就是不完整的.
五、其他的级联操作
虽然上面我们没有要自己写代码,但是通常我们是要自己来完善代码逻辑的,譬如Update的时候XCode就没有帮我们生成代码,我们只要记住一点,重载OnUpdate,并且在最后调用base.OnUpdate()方法即可.
举个实际应用中的例子,可能和级联操作没有太大关系,但是却是重载OnUpdate和OnDelete有关的,通常我们一个用户会有个头像,数据库中保存的是头像的相对地址,那么如果用户修改或删除了呢,关联的头像不就没有用了吗,如果不删除物理文件的话,那日积月累下来磁盘上的垃圾头像越来越多,我们不得不去手动清理或做其他的处理.
这个时候如果在Update或Delete的时候重载方法,加上你磁盘操作的方法就可以在编辑和删除的时候就把那些没有用的垃圾头像给清理掉了.
具体怎么写?还要我教你?好吧,我就简单的写一下吧,磁盘操作不是本节的重点,你可以在网上找到很多这样的方法.
写到这里突然想到,之前项目里碰到的问题,delete是好办,可是update的时候,各位看官想一想,Teacher.Pic= "xxx" ; Teacher.Update(); 这个时候Pic已经变了!!!! 我不知道我要去操作磁盘上哪个文件了...怎么办...怎么办...当时楼主的性能洁癖又犯了,就是不愿意查询数据库啊,死活不愿意啊.想尽各种办法,求助大石头,求助群友,最后得到的结论是象这样的update操作又不频繁!主键查询速度是最快的!性能洁癖! 所以楼主妥协了,其实这种主键查询一次数据库要不了20ms.
在写查询的时候,要自己写一个方法,强制从数据库取数据,因为这个时候Cache里的pic那个值也已经被修改了.
所以这里,就有了楼主项目里的一段代码
FindByIDFromDb是楼主重写的一个方法,目的是避免从Cache中查找数据,其实就是把下面这样的代码中,if去掉,else及后面的语句去掉,只留FindAll(_.CompanID,CompanyID)这个方法,就从数据库下SQL查找了
本节到此结束,下一节我们讲一下复杂查询,可能会分2节来讲,一节讲复杂查询如何实现,一节讲一讲大石头引以为豪的万亿级 数据量分页(楼主就是被这个性能所吸引过来的~~)
万亿级数据量分页 大石头说这个有人超越他就请客吃饭的哦~~~
本节Demo(基本没有写代码,所以...不过还是奉上Demo吧)
http://dl.dbank.com/c0672sbtuj
ps:本节代码折叠了哦~~~想要的到论坛上搜索"折叠"就能找到
XCode上手指南系列:
NewLife.XCode 上手指南
NewLife.XCode 上手指南(二) 反向工程使用举例
NewLife.Xcode 上手指南(三) 扩展属性的使用
NewLife论坛地址:
大石头博客:
NewLife.XCode开发资源目录
http://www.cnblogs.com/asxinyu/archive/2012/06/02/2532210.html