Entity Framework 4.1/4.3 之五 (DBContext 之 2 查询功能)
昨天我们讲了 DBContext的作用及它的一些相对于ObjectContext进行的优化,今天继续进行补充。我们还是用代码来说明,文章中会加入大量的代码。对了,伦敦奥运第三日,中国军团再添3金,了不起。
一、DBContext 的查询功能 (Querying with DBContext)
(1)、显示加载
前面我们已经讲过了延迟加载和预加载,这回我们来讲讲显示加载。光数据加载都整出这么多种方式。(真TMD的Fuck,此处是个人情感的发泄)
显示加载:显示加载与延迟加载很相似,都是主从数据加载分离。但不同的是,延迟加载会自动加载从数据,而显示加载我们必需要通过一个方法来明确我们要加载的数据。上菜:
显示加载使用的方法是 DBContext.Entry 方法。
private static void TestExplicitLoading() { using (var context = new BreakAwayContext()) { var query = from d in context.Destinations where d.Name == "Grand Canyon"
select d; var canyon = query.Single(); context.Entry(canyon).Collection(d => d.Lodgings).Load(); Console.WriteLine("Grand Canyon Lodging:"); foreach (var lodging in canyon.Lodgings) { Console.WriteLine(lodging.Name); } } }
从代码中可以看到,使用Entry方法来显示加载canyon,然后能加导航属性(Lodgings)来加载关联表的数据集合。可能大家对导航属性有的模糊,其实就是表和表之前的关系。比如Class 与 Student的关系是一对多的关系,一个班有多个学生。在Entity Framework中,这种关系我们称之为导航属性。当然,也有一对一的关系。多对多的关系。
(2)、显示加载中,如何确定导航属性是否被加载
IsLoaded 方法可以来判断关联表数据是否被加载(即导航属性),也就是说是否从数据库中取得了数据。
private static void TestIsLoaded() { using (var context = new BreakAwayContext()) { var canyon = (from d in context.Destinations where d.Name == "Grand Canyon"
select d).Single(); var entry = context.Entry(canyon); Console.WriteLine( "Before Load: {0}", entry.Collection(d => d.Lodgings).IsLoaded); entry.Collection(d => d.Lodgings).Load(); Console.WriteLine( "After Load: {0}", entry.Collection(d => d.Lodgings).IsLoaded); } }
输出的结果是:Before Load: False
After Load: True
二、DBContext对于实体的增、删、改 (Adding, Changing, and Deleting Entities)
(1)、单条记录的处理
1.1、增加一条新记录
private static void AddMachuPicchu() { using (var context = new BreakAwayContext()) { var machuPicchu = new Destination { Name = "Machu Picchu", Country = "Peru" }; context.Destinations.Add(machuPicchu); context.SaveChanges(); } }
可以注意到,使用了BDSet<>.Add的方法,Destinations.Add(machuPicchu); Destinations是DBSet类型。
1.2、修改一条记录
private static void ChangeGrandCanyon() { using (var context = new BreakAwayContext()) { var canyon = (from d in context.Destinations where d.Name == "Grand Canyon"
select d).Single(); canyon.Description = "227 mile long canyon."; context.SaveChanges(); } }
这里我们要提到一个批量操作的概念,就是我们可以同时新增并且对一条记录进行修改,我们来看代码:
private static void MakeMultipleChanges() { using (var context = new BreakAwayContext())
{ var niagaraFalls = new Destination { Name = "Niagara Falls", Country = "USA" }; context.Destinations.Add(niagaraFalls); var wineGlassBay = (from d in context.Destinations where d.Name == "Wine Glass Bay"
select d).Single(); wineGlassBay.Description = "Picturesque bay with beaches."; context.SaveChanges(); } }
我们来看看它发送到数据库执行的语句:可以看到同时实现了新增和编辑。这就是批量操作。
1.3、删除一条记录
private static void DeleteWineGlassBay() { using (var context = new BreakAwayContext()) { var bay = (from d in context.Destinations where d.Name == "Wine Glass Bay"
select d).Single(); context.Destinations.Remove(bay); context.SaveChanges(); } }
关于删除操作,我们要多讲讲,因为有的时候我们会去新增加的实体进行删除操作。有的时候我们也会对多表进行关联删除。那么这些情况下,Remove是如何实现的呢?我来一一分析。
先来看看删除的在理:我们先通过条件来找到一个对象,然后BDContext会对应该对象建立状态跟踪。删除时,对象必须被跟踪的更改跟踪标记为删除,savechanges建造一个删除命令发送到数据库,然后热行删除。
如果你知道你需要删除的实体,但没有执行查询来找它(也就是说,它不存在内存中),DBContext给我们提供了一个很好的操作,我们可以直接从数据库中来删除这条记录。步骤是可以添加一个替身实体,并删除这个替身实体,这时候BDContext会更改其状态为删除,savechanges建造一个删除命令发送到数据库,然后热行删除。我们来看代码:
var toDelete = new Destination { DestinationId = 2 }; context.Destinations.Attach(toDelete); context.Destinations.Remove(toDelete); context.SaveChanges();
我们通知Key DestinationId知道要删除的实体,Attach添加替身,Remove替身,SaveChanges(告诉数据库执行删除)。是不是很方便,减少了一次与数据库的交互,就是查找实体那一步。如果内在中有该实体的话,刚不能使用Attach方法,否则会报错。
当然,我们还可以利用Sql语句来执行删除,DBContext同样能办到,代码如下:
context.Database.ExecuteSqlCommand("DELETE FROM baga.Locations WHERE LocationName = 'Hawaii'");
关联删除,即对有主从关系的实体进行关联删除,我们还是直接来看代码:
private static void DeleteGrandCanyon() { using (var context = new BreakAwayContext()) { var canyon = (from d in context.Destinations where d.Name == "Grand Canyon"
select d).Single(); context.Entry(canyon) .Collection(d => d.Lodgings) .Load(); context.Destinations.Remove(canyon); context.SaveChanges(); } }
这是上面关联删除发送到数据库所执行的三条语句,实现了主从删除。
好了,我是百灵,我今天就先写到这里,我们看到了DBContext给我们提供了许许多多非常灵活的功能,如果我们都能合理利用的话,性能会得到很大的提升。当然,我讲的还不够全面,我会在后续继续跟进。有不足的地方请大家告诉我。
百灵注:本文版权由百灵和博客园共同所有,转载请注明出处。
助人等于自助! [email protected]