Entity Framework 4.1/4.3 之六 (DBContext 之 3 状态跟踪 )
Entity Framework 4.1/4.3 之六 (DBContext 之 3 状态跟踪)
咱们接着来讲DBContext,这回内容将与DBContext 2中所讲的内容连贯起来。
二、DBContext对于实体的增、删、改 (Adding, Changing, and Deleting Entities)
DBContext 2中我们讲到了“增、删、改”,其中已经讲了“增、删、改”。还有部分内容没讲,我们补全。
(1)、查找增加模式 (The “Find or Add” Pattern)
场景:我们常常会增加一条记录,增加的步骤是先查找有没有相同记录存在,如果不存在内里将新记录新增到数据库中。在老版EF中我们会执行两次操作:即先找,在增。这无形中要与数据库交互两。
DBContext为我们提供了新的解决方案,即Find or Add,我们来看看代码:
private static void FindOrAddPerson()
{
using (var context = new BreakAwayContext())
{
var ssn = 123456789;
var person = context.People.Find(ssn)?? context.People.Add(new Person
{
SocialSecurityNumber = ssn,
FirstName = "jerry",
LastName = "tom"
});
Console.WriteLine(person.FirstName);
}
}
代码看起来非常的直观,如果Find(ssn)在缓存或者数据库中找到了该记录,则输出,否则则新增一条记录。
(2)、新增关系数据(Adding a Relationship Between Objects)
说实话,这个理解起来有点绕,不好解释。我们还是直接来看下面的代码吧!
private static void NewGrandCanyonResort()
{
using (var context = new BreakAwayContext())
{
var resort = new Resort
{
Name = "Pete's Luxury Resort"
};
context.Lodgings.Add(resort);
var canyon = (from d in context.Destinations
where d.Name == "Grand Canyon"
select d).Single();
canyon.Lodgings.Add(resort);
context.SaveChanges();
}
}
Destinations 与 Lodgings 是一对多的关系,首先我们创建一个 resort 对象,将它加入到 Lodgings 集合中。然后我们找到父集合Destinations ,将resort 对象加入到Destinations包含的Lodgings集合中,然后SaveChanges,这种关联关系就建立起来了,相应的数据也保存到了数据库中。就是这么个意思,通俗的讲,就是先在从表里增加一条记录,然后将新增的记录与主表关系起来。你明白了吗?
这里我要强调一点,两表关联,对应该的关系ID要统一。比如主表中的主键是 classId ,那么相关系的从表关联id 也应该是classId,如果不统一的话,EF很难自动进行Map,除非人为的在Map文件中重改映射关系。
(3)、修改关系数据 (Changing a Relationship Between Objects)
private static void ChangeLodgingDestination()
{
using (var context = new BreakAwayContext())
{
var hotel = (from l in context.Lodgings
where l.Name == "Grand Hotel"
select l).Single();
var reef = (from d in context.Destinations
where d.Name == "Great Barrier Reef"
select d).Single();
hotel.Destination = reef;
context.SaveChanges();
}
}
这是生成Sql语句:
exec sp_executesql N'update [dbo].[Lodgings]
set [destination_id] = @0
where ([LodgingId] = @1)
',N'@0 int,@1 int',@0=4,@1=1
这里Lodgings依然扮演着从表的角色,代码暂示了主从表关系的变更。当然,这只是DBContext中给我们提供的一个解决方案。我个人习惯直接修改关联关系ID的值。
(4)、删除关系(Removing a Relationship Between Objects)
private static void RemovePrimaryContact()
{
using (var context = new BreakAwayContext())
{
var davesDump = (from l in context.Lodgings
where l.Name == "Dave's Dump"
select l).Single();
context.Entry(davesDump).Reference(l => l.PrimaryContact).Load();
davesDump.PrimaryContact = null;
context.SaveChanges();
}
}
private static void RemovePrimaryContact()
{
using (var context = new BreakAwayContext())
{
var davesDump = (from l in context.Lodgings
where l.Name == "Dave's Dump"
select l).Single();
davesDump.PrimaryContactId = null;
context.SaveChanges();
}
}
删除关系没什么好讲的,一种方式是关联子集置空,一种方式是将关联id置空。
(5)、简单描述一下跟踪状态,这里只是简单的了解,后续会有专门的详解。(Working with Change Tracking)
状态清单:• DbSet.Add
• DbSet.Find
• DbSet.Remove
• DbSet.Local
• DbContext.SaveChanges
• Running any LINQ query against a DbSet
• DbSet.Attach
• DbContext.GetValidationErrors
• DbContext.Entry
• DbChangeTracker.Entries
正是有了这些跟踪状态(Tracking),SaveChanges才知道它应该干些什么。
DetectChanges:变化检测(Controlling When DetectChanges Is Called) 控制程序将在 变化检测时被触发。
大多数情况下(或者说大多说时间),在SaveChanges期间 Entity Framework 都需要知道 Tracking Change(即跟踪状态的改变情况)。 这里有个不太好理解的定义:Automatic DetectChanges 下面是一段应用代码,因为目前我对Automatic DetectChanges还不太准确。所以只把代码展示出来,大家分析分析。
private static void ManualDetectChanges()
{
using (var context = new BreakAwayContext())
{
context.Configuration.AutoDetectChangesEnabled = false;
var reef = (from d in context.Destinations
where d.Name == "Great Barrier Reef"
select d).Single();
reef.Description = "The world's largest reef.";
Console.WriteLine(
"Before DetectChanges: {0}",
context.Entry(reef).State);
context.ChangeTracker.DetectChanges();
Using Snapshot Change Tracking | 61
Console.WriteLine(
"After DetectChanges: {0}",
context.Entry(reef).State);
}
}
private static void AddMultipleDestinations()
{
using (var context = new BreakAwayContext())
{
context.Configuration.AutoDetectChangesEnabled = false;
context.Destinations.Add(new Destination
{
Name = "Paris",
Country = "France"
});
context.Destinations.Add(new Destination
{
Name = "Grindelwald",
Country = "Switzerland"
});
context.Destinations.Add(new Destination
{
Name = "Crete",
Country = "Greece"
});
context.SaveChanges();
}
}
我总觉得这个很难理解。
(6)、使用detectchanges触发关系 (Using DetectChanges to Trigger Relationship Fix-up) (这个也是我目前不太理解的,下面是实例中的代码)
private static void DetectRelationshipChanges()
{
using (var context = new BreakAwayContext())
{
var hawaii = (from d in context.Destinations
where d.Name == "Hawaii"
select d).Single();
var davesDump = (from l in context.Lodgings
where l.Name == "Dave's Dump"
select l).Single();
context.Entry(davesDump)
.Reference(l => l.Destination)
.Load();
hawaii.Lodgings.Add(davesDump);
Console.WriteLine(
"Before DetectChanges: {0}",
davesDump.Destination.Name);
context.ChangeTracker.DetectChanges();
Console.WriteLine(
"After DetectChanges: {0}",
davesDump.Destination.Name);
}
}
希望代码能让我们明白其中的道理。
(7)、启用和使用更改跟踪代理 (Enabling and Working with Change Tracking Proxies)
(8)、确保新实例获取代理 (Ensuring the New Instances Get Proxies)
(9)、创建派生类型的代理实例(Creating Proxy Instances for Derived Types)
(10)、不更改跟踪获取实体 (Fetching Entities Without Change Tracking)
小述:6、7、8、9、10 这几种方式我没有用到,也不知道他们有什么好处和优点。如果大家了解的话,请告诉我。我先将自己用过和理解的写错来。对于一些未知的领域,也希望大家不吝指教。好了,就写到这里,我是百灵。
百灵注:本文版权由百灵和博客园共同所有,转载请注明出处。
助人等于自助! mbailing@163.com