Bagikan melalui


EF 4.2 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


 

This post will provide an introduction to Code First development and how it can be used with the 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 or Visual Studio 11 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 ‘6. Dealing with Model Changes’ 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="ProductContext"  
    providerName="System.Data.SqlClient" 
    connectionString="Server=.\SQLEXPRESS;Database=Products;Trusted_Connection=true;"/> 
</connectionStrings> 

 

1. 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
  • File -> New -> Project…
  • Select “Windows” from the left menu and “Console Application”
  • Enter “CodeFirstSample” as the name
  • Select “OK”

 

2. Create the Model

Let’s define a very simple model using classes. We’re 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 add 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; } 
} 

 

3. 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 the Entity Framework so we need to add the EntityFramework NuGet package:

  • Project –> Add Library Package Reference…
  • Select the “Online” tab
  • Select the “EntityFramework” package
  • Click “Install”

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.

 

4. Reading & Writing Data

Pad out the Main method in the 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?

By convention DbContext has created a database for you. If localhost\SQLEXPRESS is available (installed by default with Visual Studio 2010) then Code First has created the database there. If SQLEXPRESS isn’t available then Code First will try and use LocalDb (installed by default with Visual Studio 11). The database is named after the fully qualified name of your derived context, in our case that is “CodeFirstSample.ProductContext”.

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.

 

5. 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.

Replace 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(); 
    } 
  } 
} 

 

6. Dealing with Model Changes

In the next section we are going to start changing our model which in turn means the database schema needs to change as well.

EF 4.3 introduced the Code First Migrations feature that allows you to control how the database schema is evolved as your model changes.

Rather than delving into Code First Migrations in this walkthrough we are going to make use of database initializers to simply drop and re-create the database whenever the model has changed.

At the top of the Main method in the Program class add the following code:

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

 

7. 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 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 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 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

 

8. 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 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 EF. We looked at defining and configuring a model then using that model to store and retrieve data.

 

Rowan Miller

Program Manager

ADO.NET Entity Framework

Comments

  • Anonymous
    October 10, 2011
    Was MaxLengthAttribute added specifically for EF Code-First? Thanks.

  • Anonymous
    October 12, 2011
    Code samples do not wrap and are thus unreadable, even in IE.

  • Anonymous
    October 13, 2011
    The comment has been removed

  • Anonymous
    October 15, 2011
    Please, reformat the code snippets... Thanks!

  • Anonymous
    October 23, 2011
    Why did not support Unique Key on property?

  • Anonymous
    November 01, 2011
    Thanks for this, how about the enums... how do I use it.

  • Anonymous
    November 02, 2011
    Any chance we'll be getting a ".RemoveAll()" method for deleting multiple records using the Code First classes?

  • Anonymous
    November 15, 2011
    Such a good article to get start with Entity Framework. Thanks for posting. ขอบคุณนะครับ

  • Anonymous
    November 26, 2011
    I am struggling with mapping relationship to child objects, please help? social.msdn.microsoft.com/.../69d9145a-f7ec-4845-b01a-26e57e9ba16e stackoverflow.com/.../entity-framework-inheritance-zero-to-one-relationship-to-child-object-how-t

  • Anonymous
    December 15, 2011
    Why in connection string you are using "MyProductContext" name, but in DbContext class "ProductContext"?

  • Anonymous
    December 15, 2011
    It's works  :  as  [dbo].[Product] how does:      [MySchema].[Product]  

  • Anonymous
    February 05, 2012
    The comment has been removed

  • Anonymous
    February 21, 2012
    Is there a way to map a DateTimeOffset property to a SQL Server datetime column, with the assumption that you can't change either side, meaning that the property and column have to stay those date types. I know the easiest is to make them match but want to know if there's a way to work around this.

  • Anonymous
    March 30, 2012
    EF Team: What I'd really love is a Ruby-On-Rails like Entity Relationship modeler, where-in EntityFramework could infer relationships, or the user could specify relations via simple tags like "belongs_to" and "has_many". MVC 3 has done a good job copying other elements of Rails... now lets get EF copied right, and we'll be all set!

  • Anonymous
    April 01, 2012
    @Klaus: I encourage you to add this feature request in our UserVoice site so that other people can vote for it. The address is http://ef.mswish.net.

  • Anonymous
    April 01, 2012
    @Oleg Sych: We added MaxLenghtAttribute in EntityFramework.dll in 4.1 because we wanted an attribute that unlike StringLenght we could use for both strings and byte arrays. We also liked the name better. Since then this attribute has been incorporated in System.ComponentModel.DataAnnotations in .NET 4.5. You can use either implementation of the attribute as a regular data annotation besides Code First. E.g. it works for validation in MVC too.

  • Anonymous
    April 01, 2012
    @Paul: not progress yet on figuring out a "just works" solution for N-tier with Code First. I encourage you to add this feature request (of vote for it if it is already added) in our UserVoice site: http://ef.mswish.net.

  • Anonymous
    April 01, 2012
    @Flyear: EF still doesn't support unique constraints (i.e. unique keys other than the primary key). We can add a data annotation and Code First support for it once we have the feature.

  • Anonymous
    April 01, 2012
    @Merijn van Mourik: for enums support you need EF 5.0 and .NET 4.5. Once you have that you just need to make a property of an enum type and EF will pick it up. There is a walkthrough that explains enums in detail: msdn.microsoft.com/.../hh859576.

  • Anonymous
    May 16, 2012
    @Rowan - We have a legacy application and it needs to be ported over to latest and greatest. The database is  mature and has lots of data. We would like to start code first on this project so we take a leap into the latest and greatest. Here are some questions:

  1. I saw reverse engineering article on your website so we know we can start with code first on an existing db. I am seeing that that any change in model is going to drop and recreate the schema and data migration is needed. Now that is NOT something we want in the production environment and we need to keep the primary keys and the data intact. Using codebased migrations, can we do a production release(based on changes to properties, or new entities etc) by getting a sql script via sql compare and just run the script in production. Then move the code so the database is already synched and it will recognize the changes and not drop and recreate the database?
  2. Can we still have the same primary keys so keys are not changed whenever a production release happens?
  3. If the answer to 1, 2 is yes, point to me how to make these happen. Please let me know.
  • Anonymous
    May 16, 2012
    @Stan Mohr - "I am seeing that that any change in model is going to drop and recreate the schema and data migration is needed." When we first released Code First we did not have a migrations feature but starting with EF 4.3 we do, here is the best walkthrough for migrations - blogs.msdn.com/.../ef-4-3-code-based-migrations-walkthrough.aspx. Because you are working against a database that is not empty you should run 'Enable-Migrations' and then 'Add-Migration InitialCreate -IgnoreModelChanges' before you make any changes to your model that will result in changes to the database. This will give you an empty migration in your project that stores some metadata to let migrations know what your model looked like before you started changing it. Note that 'InitialCreate' is just a name for the migration, you can use any name you want.

  • Anonymous
    May 22, 2012
    I want to say Thank you fro EF developer Team i love code first approach Im looking forward for new feachers

  • Anonymous
    May 23, 2012
    Great article to start with EF code first development, explains the basic idea of CFD. Can anyone share some good links for detailed study of code first development ?

  • Anonymous
    May 29, 2012
    @Manoj Kalia - This page has some good Code First topics in the 'Going Deeper' section - msdn.microsoft.com/.../ee712907

  • Anonymous
    June 04, 2012
    Good example to start using code first!

  • Anonymous
    July 10, 2012
    In the example, if I change the Collection for an array like: public virtual ICollection<Product> Products { get; set; }  --> old public virtual Product[] Products { get; set; } --> new The Foreign keys are created on the database when I save the context (using arrays), but when I recall a Category object from the database the associated Products belonging to that Category aren't in the array. Currently there is no support for arrays instead of collections or am I doing something wrong? Is there any workaround? Thanks in advance!

  • Anonymous
    July 13, 2012
    @alexsantos89 – Arrays aren’t supported for navigation properties because they are fixed length, meaning that EF can’t add items to them.

  • Anonymous
    September 17, 2012
    I want my application to create database only when database not exists otherwise use existing database with some tables if exists and also create new tables. can we do this without Migration in code first?

  • Anonymous
    September 18, 2012
    @Delush - By default Code First will only create the database if it doesn't exist. Starting with EF5 it will also add tables to an existing database if the database doesn't contain any of the tables from your model. If the database already contains some of the tables from your model you will need to use migrations.