《Entity Framework 6 Recipes》中文翻译系列 (43) ------ 第八章 POCO之使用POCO加载实体

翻译的初衷以及为什么选择《Entity Framework 6 Recipes》来学习,请看本系列开篇

8-2  使用POCO加载关联实体

问题

  你想使用POCO预先加载关联实体。

解决方案

  假设你有如图8-3所示的模型。

图8-3. 一个包含实体Venue、Event和Competitor的模型

  实体使用POCO类,我们想预先加载关联实体(导航属性)。并使用上下文对象中的Include()方法来实现。代码清单8-4演示了使用Include()方法来实现我们的要求。

代码清单8-4. 使用Include()方法显式加载导航属性

class Program
    {
        static void Main(string[] args)
        {
            RunExample();
        }

        static void RunExample()
        {
            using (var context = new EFRecipesEntities())
            {
                var venue = new Venue { Name = "Sports and Recreational Grounds" };
                var event1 = new Event { Name = "Inter-school Soccer" };
                event1.Competitors.Add(new Competitor { Name = "St. Mary‘s School" });
                event1.Competitors.Add(new Competitor { Name = "City School" });
                venue.Events.Add(event1);
                context.Venues.Add(venue);
                context.SaveChanges();
            }
            using (var context = new EFRecipesEntities())
            {
                foreach (var venue in context.Venues.Include("Events").Include("Events.Competitors"))
                {
                    Console.WriteLine("Venue: {0}", venue.Name);
                    foreach (var evt in venue.Events)
                    {
                        Console.WriteLine("\tEvent: {0}", evt.Name);
                        Console.WriteLine("\t--- Competitors ---");
                        foreach (var competitor in evt.Competitors)
                        {
                            Console.WriteLine("\t{0}", competitor.Name);
                        }
                    }
                }
            }
            using (var context = new EFRecipesEntities())
            {
                foreach (var venue in context.Venues)
                {
                    Console.WriteLine("Venue: {0}", venue.Name);
                    context.Entry(venue).Collection(v => v.Events).Load();
                    foreach (var evt in venue.Events)
                    {
                        Console.WriteLine("\tEvent: {0}", evt.Name);
                        Console.WriteLine("\t--- Competitors ---");
                        context.Entry(evt).Collection(e => e.Competitors).Load();
                        foreach (var competitor in evt.Competitors)
                        {
                            Console.WriteLine("\t{0}", competitor.Name);
                        }
                    }
                }
            }

            Console.WriteLine("Enter input:");
            string line = Console.ReadLine();
            if (line == "exit")
            {
                return;
            };
        }
    }
    public partial class Competitor
    {
        public int CompetitorId { get; set; }
        public string Name { get; set; }
        public int EventId { get; set; }

        public virtual Event Event { get; set; }
    }
    public partial class Event
    {
        public Event()
        {
            this.Competitors = new HashSet<Competitor>();
        }

        public int EventId { get; set; }
        public string Name { get; set; }
        public int VenueId { get; set; }

        public virtual ICollection<Competitor> Competitors { get; set; }
        public virtual Venue Venue { get; set; }
    }
    public partial class Venue
    {
        public Venue()
        {
            this.Events = new HashSet<Event>();
        }

        public int VenueId { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Event> Events { get; set; }
    }
    public partial class EFRecipesEntities : DbContext
    {
        public EFRecipesEntities()
            : base("name=EFRecipesEntities")
        {        this.Configuration.LazyLoadingEnabled = false;
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public DbSet<Competitor> Competitors { get; set; }
        public DbSet<Event> Events { get; set; }
        public DbSet<Venue> Venues { get; set; }
    }

代码清单8-4的输出如下:

Venue: City Center Hall
    Event: All Star Boxing
    --- Competitors ---Big Joe Green
    Terminator Tim
Venue: Sports and Recreational Grounds
    Event: Inter-school Soccer
    --- Competitors ---St. Mary‘s School
    City School

原理

  当为我们的模型使用实体框架生成的代码时,我们使用上下文对象中的Include()方法,查询并加载关联实体,这些关联实体可能是实体的列表,可能是一个单独的实体对象 。实体框架中一共有三种不同的方法来加载或查询关联实体: Eager Loading(预先加载), Lazy Loading(延迟加载)和Explicit Loading(显式加载)。示例中我们使用Include()方法演示预先加载关联实体。默认状态下,实体框架是开启延迟加载的,但是在这里,我们把它禁用了。为了使用POCO显式加载导航属性,需要使用DbContext中的Include()方法。

8-3  使用POCO延迟加载

问题

  你想使用POCO延迟加载关联实体。

解决方案

  假设你有如图8-4所示的模型。

图8-4. 一个关于交通罚单、违规车辆和违规细节的模型

  启用延迟加载 ,你不需要做任何事。它是实体框架的默认行为 。代码清单8-5对此进行了演示。

代码清单8-5. 实体类生成,属性设置为Virtual,这是实体框架的默认行为

class Program
    {
        static void Main(string[] args)
        {
            RunExample();
        }
        static void RunExample()
        {
            using (var context = new EFRecipesEntities())
            {
                var vh1 = new Vehicle { LicenseNo = "BR-549" };
                var t1 = new Ticket { IssueDate = DateTime.Parse("06/10/13") };
                var v1 = new Violation
                {
                    Description = "20 MPH over the speed limit",
                    Amount = 125M
                };
                var v2 = new Violation
                {
                    Description = "Broken tail light",
                    Amount = 50M
                };
                t1.Violations.Add(v1);
                t1.Violations.Add(v2);
                t1.Vehicle = vh1;
                context.Tickets.Add(t1);
                var vh2 = new Vehicle { LicenseNo = "XJY-902" };
                var t2 = new Ticket { IssueDate = DateTime.Parse("06/12/13") };
                var v3 = new Violation
                {
                    Description = "Parking in a no parking zone",
                    Amount = 35M
                };
                t2.Violations.Add(v3);
                t2.Vehicle = vh2;
                context.Tickets.Add(t2);
                context.SaveChanges();
            }
            using (var context = new EFRecipesEntities())
            {
                foreach (var ticket in context.Tickets)
                {
                    Console.WriteLine(" Ticket: {0}, Total Cost: {1}",
                      ticket.TicketId.ToString(),
                      ticket.Violations.Sum(v => v.Amount).ToString("C"));
                    foreach (var violation in ticket.Violations)
                    {
                        Console.WriteLine("\t{0}", violation.Description);
                    }
                }
            }
            Console.WriteLine("Enter input:");
            string line = Console.ReadLine();
            if (line == "exit")
            {
                return;
            };
        }
    }
    public partial class Ticket
    {
        public Ticket()
        {
            this.Violations = new HashSet<Violation>();
        }

        public int TicketId { get; set; }
        public int VehicleId { get; set; }
        public System.DateTime IssueDate { get; set; }

        public virtual Vehicle Vehicle { get; set; }
        public virtual ICollection<Violation> Violations { get; set; }
    }
    public partial class Vehicle
    {
        public Vehicle()
        {
            this.Tickets = new HashSet<Ticket>();
        }

        public int VehicleId { get; set; }
        public string LicenseNo { get; set; }

        public virtual ICollection<Ticket> Tickets { get; set; }
    }
    public partial class Violation
    {
        public int ViolationId { get; set; }
        public string Description { get; set; }
        public decimal Amount { get; set; }
        public int TicketId { get; set; }

        public virtual Ticket Ticket { get; set; }
    }
 public partial class EFRecipesEntities : DbContext
    {
        public EFRecipesEntities()
            : base("name=EFRecipesEntities")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public DbSet<Ticket> Tickets { get; set; }
        public DbSet<Vehicle> Vehicles { get; set; }
        public DbSet<Violation> Violations { get; set; }
    }

代码清单8-5的输出如下:

Ticket: 1, Total Cost: $175.00
    20 MPH over the speed limit
    Broken tail light
Ticket: 2, Total Cost: $35.00
    Parking in a no parking zone

原理

  当生成一个实体数据模型时,延迟加载被默认设置。导航属性默认也被标记为virtual。使用延迟加载,你不需要显式地做任何事。

  在上面的控制台程序中,我们没有编写别的代码来加载Violation对象,它是Ticket对象的关联对象。当你在代码中访问关联实体时,延迟加载就生效了。它不需要上下文对象在第一次加载主实体时就加载关联实体,不需要像上一节中使用Include()方法显式加载关联实体。

实体框架交流QQ群:  458326058,欢迎有兴趣的朋友加入一起交流

谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/VolcanoCloud/

时间: 2024-10-11 10:18:05

《Entity Framework 6 Recipes》中文翻译系列 (43) ------ 第八章 POCO之使用POCO加载实体的相关文章

《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述 (转)

微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF版本更新太快,没人愿意去花时间翻译国外关于EF的书籍.使用Entity Framework开发已经有3年多了,但用得很肤浅,最近想深入学习,只好找来英文书<Entity Framework 6 Recipes>第二版,慢慢啃.首先需要说明的是,我英文不好,只是为了学习EF.把学习的过程写成博客,一

《Entity Framework 6 Recipes》翻译系列(2) -----第一章 开始使用实体框架之使用介绍 (转)

Visual Studio 我们在Windows平台上开发应用程序使用的工具主要是Visual Studio.这个集成开发环境已经演化了很多年,从一个简单的C++编辑器和编译器到一个高度集成.支持软件开发整个生命周期的多语言环境. Visual Studio以及它发布的工具和服务提供了:设计.开发.单元测试.调试.软件配置和管理.构建管理和持续集成等等.很少有开发人员因为还没有使用它而担心(注:作者应该是表达不用担心VS的能力),Visual Studio是一个完整的工具集.Visual Stu

《Entity Framework 6 Recipes》翻译系列 2 -----第一章 开始使用实体框架2

Visual Studio 我们在Windows平台上开发应用程序使用的工具主要是Visual Studio.这个集成开发环境已经演化了很多年,从一个简单的C++编辑器和编译器到一个高度集成.支持软件开发整个生命周期的多语言环境. Visual Studio以及它发布的工具和服务提供了:设计.开发.单元测试.调试.软件配置和管理.构建管理和持续集成等等.很少有开发人员因为还没有使用它而担心(注:作者应该是表达不用担心VS的能力),Visual Studio是一个完整的工具集.Visual Stu

《Entity Framework 6 Recipes》翻译系列 (4) -----第二章 实体数据建模基础之从已存在的数据库创建模型 (转)

不知道对EF感兴趣的并不多,还是我翻译有问题(如果是,恳请你指正),通过前几篇的反馈,阅读这个系列的人不多.不要这事到最后成了吃不讨好的事就麻烦了,废话就到这里,直奔主题. 2-2 从已存在的数据库创建模型 问题 有一个存在的数据库,它拥有表.也许还有视图.外键.你想通过它来创建一个模型. 解决方案 让我们设想,你拥有一个描述诗人(Poet)以及他们的诗(Poem),还有他们之间关系的数据库.如图2-7所示. 图2-7 一个关于诗人及他们的诗的简单数据库 从上图可以看出,一个诗人可能是一首或多首

《Entity Framework 6 Recipes》翻译系列 (3) -----第二章 实体数据建模基础之创建一个简单的模型 (转)

第二章 实体数据建模基础 很有可能,你才开始探索实体框架,你可能会问“我们怎么开始?”,如果你真是这样的话,那么本章就是一个很好的开始.如果不是,你已经建模,并在实体分裂和继承方面感觉良好,那么你可以跳过本章. 本章将带你漫游使用实体框架建模的基本实例,建模是实体框架的核心特性,同时也是区别实体框架和微软早期的数据访问平台的特性.一旦建好模,你就可以面向模型编写代码,而不用面向关系数据库中的行和列. 本章以创建一个简单概念模型的实例开始,然后让实体框架创建底层的数据库,剩下的实例,将向你展示,如

《Entity Framework 6 Recipes》翻译系列 (5) -----第二章 实体数据建模基础之有载荷和无载荷的多对多关系建模 (转)

2-3 无载荷(with NO Payload)的多对多关系建模 问题 在数据库中,存在通过一张链接表来关联两张表的情况.链接表仅包含连接两张表形成多对多关系的外键,你需要把这两张多对多关系的表导入到实体框架模型中. 解决方案 我们设想,你数据库中的表与图2-10一样. 图2-10 艺术家和专辑多对多关系 按下面的步骤将这些表和关系导入到模型中: 1.右键你的项目,选择Add(增加) ?New Item(新建项),然后选择Visual C#条目下的Data模板下的ADO.NET Entity D

《Entity Framework 6 Recipes》中文翻译系列 (45) ------ 第八章 POCO之获取原始对象与手工同步对象图和变化跟踪器

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-6  获取原始对象 问题 你正在使用POCO,想从数据库获取原始对象. 解决方案 假设你有如图8-7所示的模型.你正在离线环境下工作,你想应用在获取客户端修改之前,使用Where从句和FirstDefault()方法从数据库中获取原始对象. 图8-7.包含一个单独实体Item的模型 按代码清单8-9的方式,在获取实体之后,使用新值更新实体并将其保存到数据库中. 代码清单8-9. 获取最新

《Entity Framework 6 Recipes》中文翻译系列 (42) ------ 第八章 POCO之使用POCO

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第八章 POCO 对象不应该知道如何保存它们,加载它们或者过滤它们.这是软件开发中熟悉的口头禅,特别是在领域驱动设计中.这是一个聪明的做法,如果对象和持久化绑得太紧,以至于不能对领域对象进行单元测试.重构和复用.在ObjectContext上下对象中,实体框架为模型实体生成的类,高度依赖实体框架管道(Plumbing).对于一此开发人员来说,这些类对持久化机制知道得太多了.而且,它们与特定的

《Entity Framework 6 Recipes》中文翻译系列 (20) -----第四章 ASP.NET MVC中使用实体框架之在MVC中构建一个CRUD示例

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第四章  ASP.NET MVC中使用实体框架 ASP.NET是一个免费的Web框架,它支持3种不同的技术来创建websites(网站)和Web应用:他们分别是,Web Pages,Web Forms,和MVC.虽然MVC是一种非常流行的,有完整的用于软件开发模式理论的技术,但它在ASP.NET中却是一种新的技术. 目前最新的版本是2012年发布的ASP.NET MVC4.自从2008年发布