Udostępnij za pośrednictwem


EF 4.1 Code First Walkthrough

 


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.

For Code First to a New Database see https://msdn.com/data/jj193542

For Code First to an Existing Database see https://msdn.com/data/jj200620


 

Entity Framework 4.1 RTW is now available and is the first fully-supported go-live release of the DbContext API and Code First development workflow.

This post will provide an introduction to Code First development and how it can be used with the new DbContext API surface. Code First allows you to define your model using C# or VB.Net classes, optionally additional configuration can be performed using attributes on your classes and properties or by using a Fluent API. Your model can be used to generate a database schema or to map to an existing database.

You will need to have Visual Studio 2010 installed to complete this walkthrough.

Mapping to an Existing Database

This walkthrough is going to demonstrate Code First generating the database schema but the same principals apply to mapping to an existing database, with the exception of ‘7. Setting an Initialization Strategy’ which does not apply to existing databases. If Code First is pointed at an existing database that it did not create then it will just attempt to use the specified configuration to access the database. The easiest way to point Code First to an existing database is to add a App/Web.config connection string with the same name as your derived DbContext, for example;

 <connectionStrings>
  <add 
    name="MyProductContext" 
    providerName="System.Data.SqlClient" 
    connectionString="Server=.\SQLEXPRESS;Database=Products;Trusted_Connection=true;"/>
</connectionStrings>

 

1. Install EF 4.1

If you haven’t already done so then you need to install Entity Framework 4.1

 

2. Create the Application

To keep things simple we’re going to build up a basic console application that uses the Code First to perform data access:

  • Open Visual Studio 2010
  • File -> New -> Project…
  • Select “Windows” from the left menu and “Console Application”
  • Enter “CodeFirstSample” as the name
  • Select “OK”

 

3. Create the Model

Let’s define a very simple model using classes. I’m just defining them in the Program.cs file but in a real world application you would split your classes out into separate files and potentially a separate project.

Below the Program class definition in Program.cs I am defining the following two classes:

 public class Category
{
    public string CategoryId { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Product> Products { get; set; }
}

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public string CategoryId { get; set; }

    public virtual Category Category { get; set; }
} 

 

4. Create a Context

The simplest way to start using the classes for data access is to define a context that derives from System.Data.Entity.DbContext and exposes a typed DbSet<TEntity> for each class in my model.

We’re now starting to use types from EF 4.1 so we need to add a reference to the EntityFramework assembly:

  • Project -> Add Reference…
  • Select the “.NET” tab
  • Select “EntityFramework” from the list
  • Click “OK”

You’ll also need a reference to the existing Entity Framework assembly:

  • Project -> Add Reference…
  • Select the “.NET” tab
  • Select “System.Data.Entity” from the list
  • Click “OK”

Add a using statement for System.Data.Entity at the top of Program.cs

 using System.Data.Entity;

Add a derived context below the existing classes that we’ve defined

 public class ProductContext : DbContext
{
    public DbSet<Category> Categories { get; set; }
    public DbSet<Product> Products { get; set; }
}

That is all the code we need to write to start storing and retrieving data. Obviously there is quite a bit going on behind the scenes and we’ll take a look at that in a moment but first let’s see it in action.

5. Reading & Writing Data

I’m padding out the Main method in my program class as follows:

 class Program
{
    static void Main(string[] args)
    {
        using (var db = new ProductContext())
        {
            // Add a food category 
            var food = new Category { CategoryId = "FOOD", Name = "Foods" };
            db.Categories.Add(food);
            int recordsAffected = db.SaveChanges();

            Console.WriteLine(
                "Saved {0} entities to the database, press any key to exit.",
                recordsAffected);

            Console.ReadKey();
        }
    }
} 

You can now run the application and see that the new category is inserted.

Where’s My Data?

DbContext by convention created a database for you on localhost\SQLEXPRESS. The database is named after the fully qualified name of your derived context, in our case that is “CodeFirstSample.ProductContext”. We’ll look at ways to change this later in the walkthrough.

Model Discovery

DbContext worked out what classes to include in the model by looking at the DbSet properties that we defined. It then uses the default Code First conventions to find primary keys, foreign keys etc.

 

6. Reading & Writing More Data

Let’s pad out the program we just wrote to show a bit more functionality. We are going to make use of the Find method on DbSet that will locate an entity based on primary key. If no match is found then Find will return null. We’re also making use of LINQ to query for all products in the Food category ordered alphabetically by name. Querying uses the exiting LINQ to Entities provider so it supports the same queries that are possible with ObjectSet/ObjectQuery in EF4.

I’m replacing the Main we wrote above with the following:

 class Program
{
    static void Main(string[] args)
    {
        using (var db = new ProductContext())
        {
            // Use Find to locate the Food category 
            var food = db.Categories.Find("FOOD");
            if (food == null)
            {
                food = new Category { CategoryId = "FOOD", Name = "Foods" };
                db.Categories.Add(food);
            }

            // Create a new Food product 
            Console.Write("Please enter a name for a new food: ");
            var productName = Console.ReadLine();

            var product = new Product { Name = productName, Category = food };
            db.Products.Add(product);

            int recordsAffected = db.SaveChanges();

            Console.WriteLine(
                "Saved {0} entities to the database.",
                recordsAffected);

            // Query for all Food products using LINQ 
            var allFoods = from p in db.Products
                            where p.CategoryId == "FOOD"
                            orderby p.Name
                            select p;

            Console.WriteLine("All foods in database:");
            foreach (var item in allFoods)
            {
                Console.WriteLine(" - {0}", item.Name);
            }

            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
    }
} 

 

7. Setting an Initialization Strategy

In the next section we are going to start changing our model which in turn means the database schema needs to change as well. Currently there is no ‘out of the box’ solution to evolve your existing schema in place. Database evolution is something we are currently working on and a sample of the direction we are heading is provided in a recent design blog post.

There is however the opportunity to run some custom logic to initialize the database the first time a context is used in an AppDomain. This is handy if you want to insert seed data for test runs but it’s also useful to re-create the database if the model has changed. In EF 4.1 we include a couple of strategies you can plug in but you can also write custom ones.

 

For the walkthrough we just want to drop and re-create the database whenever the model has changed, so at the top of the Main method in my Program class I’ve added the following code

 Database.SetInitializer<ProductContext>(
    new DropCreateDatabaseIfModelChanges<ProductContext>());

 

8. Data Annotations

So far we’ve just let EF discover the model using its default conventions but there are going to be times when our classes don’t follow the conventions and we need to be able to perform further configuration. There are two options for this; we’ll look at Data Annotations in this section and then the fluent API in the next section.

Let’s add a supplier class to our model:

 public class Supplier
{
    public string SupplierCode { get; set; }
    public string Name { get; set; }
}

And we also need to add a set to our derived context

 public class ProductContext : DbContext
{
    public ProductContext()
    { }

    public DbSet<Category> Categories { get; set; }
    public DbSet<Product> Products { get; set; }
    public DbSet<Supplier> Suppliers { get; set; }
}

Now if we ran our application we’d get an InvalidOperationException saying “EntityType 'Supplier' has no key defined. Define the key for this EntityType.” because EF has no way of knowing that SupplierCode should be the primary key for Supplier.

We’re going to use Data Annotations now so we need to add a reference:

  • Project -> Add Reference…
  • Select the “.NET” tab
  • Select “System.ComponentModel.DataAnnotations” from the list
  • Click “OK

Add a using statement at the top of Program.cs:

 using System.ComponentModel.DataAnnotations;

Now we can annotate the SupplierCode property to identify that it is the primary key:

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

The full list of annotations supported in EF 4.1 is;

  • KeyAttribute

  • StringLengthAttribute

  • MaxLengthAttribute

  • ConcurrencyCheckAttribute

  • RequiredAttribute

  • TimestampAttribute

  • ComplexTypeAttribute

  • ColumnAttribute

    Placed on a property to specify the column name, ordinal & data type

  • TableAttribute

    Placed on a class to specify the table name and schema

  • InversePropertyAttribute

    Placed on a navigation property to specify the property that represents the other end of a relationship

  • ForeignKeyAttribute

    Placed on a navigation property to specify the property that represents the foreign key of the relationship

  • DatabaseGeneratedAttribute

    Placed on a property to specify how the database generates a value for the property (Identity, Computed or None)

  • NotMappedAttribute

    Placed on a property or class to exclude it from the database

 

9. Fluent API

In the previous section we looked at using Data Annotations to supplement or override what was detected by conventions. The other way to further configure the model is via the Code First fluent API. The fluent API is considered a more advanced feature and we would recommend using Data Annotations unless your requirements require you to use the fluent API.

To access the fluent API we override the OnModelCreating method in DbContext, in the following code we are using the fluent API to configure the Name property on Supplier to be required.

 public class ProductContext : DbContext
{
    public ProductContext()
    { }

    public DbSet<Category> Categories { get; set; }
    public DbSet<Product> Products { get; set; }
    public DbSet<Supplier> Suppliers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Supplier>()
            .Property(s => s.Name)
            .IsRequired();
    }
}

 

Summary

In this walkthrough we looked at Code First development using the EF 4.1. We looked at defining and configuring a model, storing and retrieving data, configuring the database connection, updating the database schema as our model evolved and validating data before it is written to the database.

Support

This is a fully supported release. The ADO.NET Entity Framework Forum can be used for questions relating to this release. Further information about getting technical support can be found at the Microsoft Support website.

Rowan Miller

Program Manager

ADO.NET Entity Framework

Comments

  • Anonymous
    March 17, 2011
    could you give an example about Table Per Type inheritance? ToolsReady@live.com

  • Anonymous
    March 17, 2011
    Did you also experience the problem that it can not find [NotMapped] attribute? I have checked and added the references to both System.ComponentModel.DataAnnotations.dll and EntityFramework.dll. In EF CTP5 this attribute resided in DataAnnotations, but where is it now?

  • Anonymous
    March 17, 2011
    I solved my problem. All that is needed is the MSDN document. Thank you so much for you good job!

  • Anonymous
    March 17, 2011
    why I'm getting "CREATE DATABASE permission denied in database 'master'." this error?

  • Anonymous
    March 17, 2011
    Is it like ConcurrencyCheckAttribute doesnt do any schema related changes? I cannot see Unique constraint created in table. Please guide.

  • Anonymous
    March 18, 2011
    @ATM: Have you tried running the app/VS as administrator (Right click "Run as Administrator)?

  • Anonymous
    March 19, 2011
    First let me say I love code first!  One quick request, when you change the model without changing the database and run the application it throws an exception which I like.  But it would be really cool if you displayed which columns/tables are causing the exception.  It would make it easier to update the DB as needed. Thanks for the great work.

  • Anonymous
    March 19, 2011
    How can I change the location of the db? I want to use a SqlServer CE database and I want to specify the location of the db.

  • Anonymous
    March 20, 2011
    hi! here's my problem . I have the following entities. conference -> has many sessions. each session has a time slot. I can add a session to the conference. but when I try to update the session I get  A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship. I cannot figure out where the issue is. ALSO The time slot entity is defined as..  public int Id { get; set; }          public string EndTime { get; set; }        public string StartTime { get; set; }        public ConferenceSession ConferenceSession { get; set; } BUT the DB does not have a FK on ConferenceSession of a link back from The time slot entity.. Some guidance please.. Thanks Bob

  • Anonymous
    March 22, 2011
    Code-First thing in the Entity Framework is great. But.. wouldn't it be cool to have a some sort of new enhanced ClassDiagram tool for it? Which would behave more like an Entity Designer, able to preserve order of the properties, show metadata (like keys, datatypes), show relationships between objects etc. based on the data annotation attributes attached to POCO classes and their members. data.uservoice.com/.../1547469

  • Anonymous
    April 04, 2011
    Hi All, Wouldn't run as I did not have SQL Server Express installed. Not sure where I change the connection string?  Looks great though :-)

  • Anonymous
    April 06, 2011
    @ Martin Erskine the DbContext has some override versions ,you can pass a connectionString like that public CategoryContext(): base(connectionString){}

  • Anonymous
    April 11, 2011
    i need a parent/children relation in 1 table, like that: public class Category {    public string CategoryId { get; set; }    public string Name { get; set; }    public virtual Category ParentCategory { get; set; }    public virtual ICollection<Category> ChildCategories{ get; set; } } when i creating db tables, there is error occurred. how to make this to work? thank you.

  • Anonymous
    April 12, 2011
    When we define "Category" and "Product" class we didn't annotate the primary key, howerver, we have to annotate that in the "Supplier" class,Why?

  • Anonymous
    April 12, 2011
    I follow instructions below but have this exception while running the project : The type 'TestEFCodeFirst.Program+Category' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive, nested or generic, and does not inherit from EntityObject.

  • Anonymous
    April 13, 2011
    @Minsou do not att the classes (e.g. Category) as nested class. Simply move them to the namespace TestEFCodeFirst.

  • Anonymous
    April 27, 2011
    This looks very clunky in comparisson to EJB3. Why not copy EJB model which is a lot more readable?

  • Anonymous
    May 02, 2011
    You mentioned in Step 5 about finding the data and changing the strategy EF uses to find the database. Is there a way to change the way EF names my database? Instead of "CodeFirstSample.ProductContext", is there a way to have "CodeFirstSample"?

  • Anonymous
    May 11, 2011
    This is really great, especially in conjuntion with MVC3/Scaffolding.  Could you provide some guidance around mapping when using Enterprise Library 5.0 Validation Application Block?  I assume there would be duplicate validations picked up by MVC/other consumers if both DataAnnotations attributes and Validation Block attributes were used on a property.  And it seems rather redundant to use fluent mapping to drive these mappings, when some of this would already be specified in Enterprise Library Validators/ValidatorAttributes (which derive from DataAnnotations.ValidationAttribute).

  • Anonymous
    May 26, 2011
    The comment has been removed

  • Anonymous
    June 20, 2011
    Hi, I would appreciate guidance on whether I am able to model the following using EF 4.1.  Business Units and Counterparties can have an arbitary number of Contacts.  A Contact can only belong to a single Entity (i.e. Business Unit or Counterparty). public class Contact {   public int Id  { get; set; }   <some other Contact details here> } public class BusinessUnit {   public int Id { get; set; }   public List<Contact> Contacts  { get; set; }   <some other Business Unit details here> } public class Counterparty {   public int Id { get; set; }   public List<Contact> Contacts  { get; set; }   <some other Counterparty details here> } public class BusinessUnitContact {   public int BusinessUnitId  { get; set; }   public int ContactId  { get; set; } } public class CounterpartyContact {   public int CounterpartyId  { get; set; }   public int ContactId  { get; set; } } The relationships are: Business Unit <-> BusinessUnitContact <-> Contact Counterparty <-> CounterpartyContact <-> Contact Thank you kindly. Tony

  • Anonymous
    June 22, 2011
    Here's a forum post that explains how Code First makes relations between classes and their tables: forums.asp.net/.../1 I had to search hard to understand this - hope this helps someone else :)

  • Anonymous
    June 18, 2012
    All of the examples that I've seen for the Entity Framework have used ICollection versus IQueryable. It seems like IQueryable would be the desired interface to use for LINQ to SQL so why ICollection?

  • Anonymous
    June 18, 2012
    The comment has been removed

  • Anonymous
    August 02, 2013
    nice

  • Anonymous
    December 25, 2013
    msdn.microsoft.com/.../jj200620

  • Anonymous
    April 15, 2015
    Good Article n very helpful to understand the things.

  • Anonymous
    May 04, 2015
    333333333333333333333333333333333333333333333333333333333333333333333333333