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

posted @ 2012-08-01 14:53  jerry-Tom  阅读(3291)  评论(10编辑  收藏  举报