Using DbContext in EF 4.1 Part 1: Introduction and Model

 


The information in this post is out of date.

Visit msdn.com/data/ef for the latest information on current and past releases of EF.


 

Introduction

Version 4.1 of the Entity Framework contains both the Code First approach and the new DbContext API. This API provides a more productive surface for working with the Entity Framework and can be used with the Code First, Database First, and Model First approaches. This is the first post of a twelve part series containing collections of patterns and code fragments showing how features of the new API can be used.

The posts in this series do not contain complete walkthroughs. If you haven’t used EF 4.1 before then you should read Code First Walkthrough or Model and Database First with DbContext before tackling this post.

Series Contents

Part 1: Introduction and Model

  • Introduces the topics that will be covered in the series
  • Presents a Code First model that will be used in the subsequent parts

Part 2: Connections and Models

  • Covers using DbContext constructors to configure the database connection and set the context to work in Code First, Model First, or Database First mode
  • Shows different ways that the DbSet properties on the context can be defined

Part 3: Finding Entities

  • Shows how an entity can be retrieved using its primary key value.

Part 4: Add/Attach and Entity States

  • Shows different ways to add a new entity to the context or attach an existing entity to the context
  • Covers the different entity states and shows how to change the state of an entity

Part 5: Working with Property Values

  • Shows how to get and set the current and original values of individual properties
  • Covers different ways of working with all the property values of an entity
  • Shows how to get and set the modified state of a property
  • Covers the loading related entities eagerly, lazily, and explicitly

Part 7: Local Data

  • Shows how to work locally with entities that are already being tracked by the context
  • Provides some general information on the facilities provided by DbContext for data binding

Part 8: Working with Proxies

  • Presents some useful tips for working with dynamically generated entity proxies

Part 9: Optimistic Concurrency Patterns

  • Shows some common patterns for handling optimistic concurrency exceptions

Part 10: Raw SQL Queries

  • Shows how to send raw queries and commands to the database

Part 11: Load and AsNoTracking

  • Covers the Load and AsNoTracking LINQ extension methods for loading entities into the context and querying entities with having them be tracked by the context

Part 12: Automatically Detecting Changes

  • Describes when and how DbContext automatically detects changes in entities provides some pointers for when to switch this off

The Model

Many of the code fragments in the posts of this series make use of the following Code First model. Assume that the context and entity types used in the fragments are from this model unless they are explicitly defined differently in the post.

The code below can be pasted into Program.cs of a standard C# console application and many of the code fragments can then be tested by inserting them into the Main method.

Model Description

The model below contains four entity types: Princess, Unicorn, Castle, and LadyInWaiting. A princess can have many unicorns and each unicorn is owned by exactly one princess. A princess has exactly one lady-in-waiting in each castle.

A castle has a location represented by the complex type Location, which in turn has a nested complex type ImaginaryWorld

Model Code

 using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Metadata.Edm;
using System.Data.Objects;
using System.Linq;

namespace Magic.Unicorn
{
    public class Princess : IPerson
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Unicorn> Unicorns { get; set; }
        public virtual ICollection<LadyInWaiting> LadiesInWaiting { get; set; }
    }

    public class Unicorn
    {
        public int Id { get; set; }
        public string Name { get; set; }

        [Timestamp]
        public byte[] Version { get; set; }

        public int PrincessId { get; set; } // FK for Princess reference
        public virtual Princess Princess { get; set; }
    }

    public class Castle
    {
        [Key]
        public string Name { get; set; }

        public Location Location { get; set; }

        public virtual ICollection<LadyInWaiting> LadiesInWaiting { get; set; }
    }

    [ComplexType]
    public class Location
    {
        public string City { get; set; }
        public string Kingdom { get; set; }

        public ImaginaryWorld ImaginaryWorld { get; set; }
    }

    [ComplexType]
    public class ImaginaryWorld
    {
        public string Name { get; set; }
        public string Creator { get; set; }
    }

    public class LadyInWaiting : IPerson
    {
        [Key, Column(Order = 0)]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int PrincessId { get; set; } // FK for Princess reference

        [Key, Column(Order = 1)]
        public string CastleName { get; set; } // FK for Castle reference

        public string FirstName { get; set; }
        public string Title { get; set; }

        [NotMapped]
        public string Name
        {
            get
            {
                return String.Format("{0} {1}", Title, FirstName);
            }
        }

        public virtual Castle Castle { get; set; }
        public virtual Princess Princess { get; set; }
    }

    public interface IPerson
    {
        string Name { get; }
    }

    public class UnicornsContext : DbContext
    {
        public DbSet<Unicorn> Unicorns { get; set; }
        public DbSet<Princess> Princesses { get; set; }
        public DbSet<LadyInWaiting> LadiesInWaiting { get; set; }
        public DbSet<Castle> Castles { get; set; }
    }

    public class UnicornsContextInitializer : DropCreateDatabaseAlways<UnicornsContext>
    {
        protected override void Seed(UnicornsContext context)
        {
            var cinderella = new Princess { Name = "Cinderella" };
            var sleepingBeauty = new Princess { Name = "Sleeping Beauty" };
            var snowWhite = new Princess { Name = "Snow White" };

            new List<Unicorn>
            {
                new Unicorn { Name = "Binky" , Princess = cinderella },
                new Unicorn { Name = "Silly" , Princess = cinderella },
                new Unicorn { Name = "Beepy" , Princess = sleepingBeauty },
                new Unicorn { Name = "Creepy" , Princess = snowWhite }
            }.ForEach(u => context.Unicorns.Add(u));

            var efCastle = new Castle
            {
                Name = "The EF Castle",
                Location = new Location
                {
                    City = "Redmond",
                    Kingdom = "Rainier",
                    ImaginaryWorld = new ImaginaryWorld
                    {
                        Name = "Magic Unicorn World",
                        Creator = "ADO.NET"
                    }
                },
            };

            new List<LadyInWaiting>
            {
                new LadyInWaiting { Princess = cinderella,
                                    Castle = efCastle,
                                    FirstName = "Lettice",
                                    Title = "Countess" },
                new LadyInWaiting { Princess = sleepingBeauty,
                                    Castle = efCastle,
                                    FirstName = "Ulrika",
                                    Title = "Lady" },
                new LadyInWaiting { Princess = snowWhite,
                                    Castle = efCastle,
                                    FirstName = "Yolande",
                                    Title = "Duchess" }
            }.ForEach(l => context.LadiesInWaiting.Add(l));
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            Database.SetInitializer(new UnicornsContextInitializer());

            // Many of the code fragments can be run by inserting them here
        }
    }
}

Summary

In this part of the series we introduced the topics that will be covered in upcoming parts and also defined a Code First model to work with.

As always we would love to hear any feedback you have by commenting on this blog post.

For support please use the Entity Framework Forum.

Arthur Vickers

Developer

ADO.NET Entity Framework