Partager via


Using DbContext in EF 4.1 Part 2: Connections and Models

 


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 Connections and Models see https://msdn.com/data/jj592674


 

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 second 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 Part 1 of this series and also Code First Walkthrough or Model and Database First with DbContext before tackling this post.

Using DbContext constructors

Typically an Entity Framework application uses a class derived from DbContext, as shown in the Code First and Model and Database First with DbContext walkthroughs. This derived class will call one of the constructors on the base DbContext class to control:

  • How the context will connect to a database—i.e. how a connection string is found/used
  • Whether the context will use Code First, Database First, or Model First
  • Additional advanced options

The following fragments show some of the ways the DbContext constructors can be used.

Use Code First with connection by convention

If you have not done any other configuration in your application, then calling the parameterless constructor on DbContext will cause DbContext to run in Code First mode with a database connection created by convention. For example:

 namespace Magic.Unicorn
{
    public class UnicornsContext : DbContext
    {
        public UnicornsContext()
        // C# will call base class parameterless constructor by default
        {
        }
    }
}

In this example DbContext uses the namespace qualified name of your derived context class—Magic.Unicorn.UnicornsContext—as the database name and creates a connection string for this database using SQL Express on your local machine.

Use Code First with connection by convention and specified database name

If you have not done any other configuration in your application, then calling the string constructor on DbContext with the database name you want to use will cause DbContext to run in Code First mode with a database connection created by convention to the database of that name. For example:

 public class UnicornsContext : DbContext
{
    public UnicornsContext()
        : base("UnicornsDatabase")
    {
    }
}

In this example DbContext uses “UnicornsDatabase” as the database name and creates a connection string for this database using SQL Express on your local machine.

Use Code First with connection string in app.config/web.config file

You may choose to put a connection string in your app.config or web.config file. For example:

 configuration>
  <connectionStrings>
    <add name="UnicornsCEDatabase"
         providerName="System.Data.SqlServerCe.4.0"
         connectionString="Data Source=Unicorns.sdf"/>
  </connectionStrings>
</configuration>

This is an easy way to tell DbContext to use a database server other than SQL Express—the example above specifies a SQL Server Compact Edition database.

If the name of the connection string matches the name of your context (either with or without namespace qualification) then it will be found by DbContext when the parameterless constructor is used. If the connection string name is different from the name of your context then you can tell DbContext to use this connection in Code First mode by passing the connection string name to the DbContext constructor. For example:

 public class UnicornsContext : DbContext
{
    public UnicornsContext()
        : base("UnicornsCEDatabase")
    {
    }
}

Alternatively, you can use the form “name=<connection string name>” for the string passed to the DbContext constructor. For example:

 public class UnicornsContext : DbContext
{
    public UnicornsContext()
        : base("name=UnicornsCEDatabase")
    {
    }
}

This form makes it explicit that you expect the connection string to be found in your config file. An exception will be thrown if a connection string with the given name is not found.

Database/Model First with connection string in app.config/web.config file

Database or Model First is different from Code First in that your Entity Data Model (EDM) already exists and is not generated from code when the application runs. The EDM typically exists as an EDMX file created by the Entity Designer in Visual Studio. The designer will also add an EF connection string to your app.config or web.config file. This connection string is special in that it contains information about how to find the information in your EDMX file. For example:

<configuration>

<connectionStrings>

<add name="Northwind_Entities"

connectionString="metadata=res://*/Northwind.csdl|

res://*/Northwind.ssdl|

res://*/Northwind.msl;

provider=System.Data.SqlClient;

provider connection string=

&quot;Data Source=.\sqlexpress;

Initial Catalog=Northwind;

Integrated Security=True;

MultipleActiveResultSets=True&quot;"

providerName="System.Data.EntityClient"/>

</connectionStrings>

</configuration>

You can tell DbContext to use this connection by passing the connection string name to the DbContext constructor. For example:

 public class NorthwindContext : DbContext
{
    public NorthwindContext()
        : base("name=Northwind_Entities")
    {
    }
}

DbContext knows to run in Database/Model First mode because the connection string is an EF connection string containing details of the EDM to use.

Other DbContext constructor options

The DbContext class contains other constructors and usage patterns that enable some more advanced scenarios. Some of these are:

  • You can use the DbModelBuilder class to build a Code First model without instantiating a DbContext instance. The result of this is a DbModel object. You can then pass this DbModel object to one of the DbContext constructors when you are ready to create your DbContext instance.
  • You can pass a full connection string to DbContext instead of just the database or connection string name. By default this connection string is used with the System.Data.SqlClient provider; this can be changed by setting a different implementation of IConnectionFactory onto context.Database.DefaultConnectionFactory.
  • You can use an existing DbConnection object by passing it to a DbContext constructor. If the connection object is an instance of EntityConnection, then the model specified in the connection will be used in Database/Model First mode. If the object is an instance of some other type—for example, SqlConnection—then the context will use it for Code First mode.
  • You can pass an existing ObjectContext to a DbContext constructor to create a DbContext wrapping the existing context. This can be used for existing applications that use ObjectContext but which want to take advantage of DbContext in some parts of the application.

Defining sets on a derived context

DbContext with DbSet properties

The common case shown in Code First examples is to have a DbContext with public automatic DbSet properties for the entity types of your model. For example:

 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; }
}

When used in Code First mode, this will configure Unicorn, Princess, LadyInWaiting, and Castle as entity types, as well as configuring other types reachable from these. In addition DbContext will automatically call the setter for each of these properties to set an instance of the appropriate DbSet.

DbContext with IDbSet properties

There a situations, such as when creating mocks or fakes, where it is more useful to declare your set properties using an interface. In such cases the IDbSet interface can be used in place of DbSet. For example:

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

This context works in exactly the same way as the context that uses the DbSet class for its set properties.

DbContext with read-only set properties

If you do not wish to expose public setters for your DbSet or IDbSet properties you can instead create read-only properties and create the set instances yourself. For example:

 public class UnicornsContext : DbContext
{
    public IDbSet<Unicorn> Unicorns
    {
        get { return Set<Unicorn>(); }
    }

    public IDbSet<Princess> Princesses
    {
        get { return Set<Princess>(); }
    }

    public IDbSet<LadyInWaiting> LadiesInWaiting
    {
        get { return Set<LadyInWaiting>(); }
    }

    public IDbSet<Castle> Castles
    {
        get { return Set<Castle>(); }
    }
}

Note that DbContext caches the instance of DbSet returned from the Set method so that each of these properties will return the same instance every time it is called.

Discovery of entity types for Code First works in the same way here as it does for properties with public getters and setters.

Summary

In this part of the series we showed how to use the various constructors on DbContext to configure connection strings and the Code First, Model First, or Database First mode of the context. We also looked at the different ways that sets can be defined on a derived context.

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

Comments

  • Anonymous
    January 27, 2011
    This is great.  Can't wait for the completion of the rest of the topics.  Thanks!!!

  • Anonymous
    January 30, 2011
    Examples can send me  one? Email:passvcword@126.com

  • Anonymous
    January 30, 2011
    Does any of this change is you are connecting to SQL Server as opposed to SQL Server Express?

  • Anonymous
    February 02, 2011
    @Gene The only part that is SQL Express specific is the connection that is built by the default convention if no other connection information is provided. You could change this default convention to use a different database, but it's usally easier to just add a connection string to your config file in which case there is nothing SQL Express specific.

  • Anonymous
    February 02, 2011
    Is it possible to access mapping metadata in Code-first,  or DbContext generated from EDMX?

  • Anonymous
    February 07, 2011
    @Ladislav If by "mapping metadata" you mean the mapping between the conceptual model and the store model (aka the ".msl" file) then the answer is no--there is no way to access this information publicly as of now. This is something we hope to enable in the future. If you mean something else by "mapping metadata" then answer is maybe but you'll need to give some more details on what specifically you are looking for.

  • Anonymous
    February 08, 2011
    how code first handle the following. I have existing database ("mystore") and table called ("customers") in code i have created class called "CustomerSummary" which has just 2 fields "Id" and "Description". How do I map CustomerSummary" (my class) to the "Customers" (data table) with just 2 field mapped. what is the steps?

  • Anonymous
    February 17, 2011
    I need to be able to configure two instances to the same DbContext derived type to two entries in the config file.   I need to be able to set the connection string after the DbContext is constructed but before any connections are opened.

  • Anonymous
    February 17, 2011
    the message "Thanks for sharing your comment!" should be in a popup.  I pressed the post button and the screen didn't even scroll to that message so I had no feedback that my post was submitted

  • Anonymous
    February 17, 2011
    @achu I would suggest you look at the Code First walkthough referenced at the top of this post. One option is to put NotMappedAttribute on the properties of your class that you don't want to map. @Darren You should be able to pass the name of the connection string you want to the DbContext constructor for each instance you are creating. There is currently no way to set connection string after the context has been created, but this is something we are considering adding for a future release.

  • Anonymous
    March 16, 2011
    Are there any examples of defining a DBContext per http request so all the db calls/transactions per model are wrapped up and use the same context?

  • Anonymous
    May 15, 2011
    I have created a DbContext class that points to schema in a sqlite db and I have SQLite library compiled and fixed. I would like to pass in the connection string to DbContext from by CustomDBContext at runtime instead of from config file. The reason is that the connection string is created programmatically. It appears that that its possible to create Entity framework model and database first strings from EntityConnectionStringBuilder class which accepts a providerName to specify the provider. However, it does not work for code first. Can you please suggest how to create connection string along with provider name that can be passed to DbContext's constructor when constructing my CustomDbContext?

  • Anonymous
    May 15, 2011
    I solved it as mentioned in my forum question... However I wonder if its inline with recommended practices. social.msdn.microsoft.com/.../b6f5c7f1-428d-48f8-84af-d3a39026011e Can you please confirm?

  • Anonymous
    May 18, 2011
    Thanks for your post. I'm in love with it. I will start using it immediately as soon as it's supported by WCF-RIA! As per the set method, I checked and it containes two methods, one generic and one that takes a Type so it can be dynamically retrieved, this is gorgeous!! I would like to notice, that in EF4, GetEntitySetName for a subclass returned an error, because only the superclass (i.e. the one that inherits from EntityObject) had a matching set. so I had to do it like this (from the partial class in the ObjectContext - note, this is intended for generated EntityObjects only): Per my code, I hope this issue is solved in EF4.1 (i.e. when I call Set<SallariedEmployee> and there is no matching set, it should return Set<Employee>().OfType<SallariedEmployee>. Or there should at least be another workaround, but it shouldn't throw exception. same should be with a runtime type (as opposed to generic)    public string GetEntitySetName(Type entityType)    {      if (entityType == null)        throw new ArgumentNullException("entityType");      if (!entityType.IsSubclassOf(typeof(EntityObject)))        throw new ArgumentException("Only subclasses of EntityObject are supported.", "entityType");      return GetEntitySetNameInternal(entityType);    }    public string GetEntitySetName<TEntity>() where TEntity : EntityObject    {      var entityType = typeof(TEntity);      return GetEntitySetNameInternal(entityType);    }                                                  private string GetEntitySetNameInternal(Type entityType)    {      string entitySetName;      if (!EntitySetNames.TryGetValue(entityType, out entitySetName))      {        while (entityType.BaseType != typeof(EntityObject))          entityType = entityType.BaseType;        var container = MetadataWorkspace.GetEntityContainer(DefaultContainerName, DataSpace.CSpace);        var entitySet = container.BaseEntitySets.SingleOrDefault(e => e.ElementType.Name == entityType.Name);        entitySetName = entitySet.Name;        EntitySetNames.Add(entityType, entitySetName);      }      return entitySetName;    }    private IDictionary<Type, string> _EntitySetNames;    public IDictionary<Type, string> EntitySetNames    {      get      {        return _EntitySetNames ?? (_EntitySetNames = new Dictionary<Type, string>());      }    }

  • Anonymous
    May 25, 2011
    DbContext with read-only set properties: It's also possible to define a set as followed: public DbSet<Unicorn> Unicorns { get; private set; } Pretty cool and very helpful. Thx for that!

  • Anonymous
    May 30, 2011
    I just saw that the above mentioned private setter only works when table-mapping is done manually and not by the code-first-convention. So when you map the Unicorns with the fluent-api to the database-table then the private setter can be used. Anyway - pretty cool ;-)

  • Anonymous
    July 30, 2011
    Could you please tell me how can I do this here?: var ctxBuilder = new ContextBuilder<TContext>(); var cs = System.Configuration.ConfigurationSettings.AppSettings["ConnectionString.SQL Server (SqlClient)"]; return ctxBuilder.Create(new SqlConnection(cs)); Actually it's part of a generic class for creating context from all models in my application.

  • Anonymous
    August 17, 2011
    Check out this simple trick to use code first with Sql Server 2008 (instead of express) without using connection string just like express dotnetech.wordpress.com/.../entity-framework-code-first-with-sql-server

  • Anonymous
    September 24, 2011
    How can you create a derived DbContext and use the instance without having a database connection?  I want to write some unit tests for some DbContext extensions I have written.  So I want to create some new objects and attach them to the context.  However, I can't do this since the context keeps looking for a connection string.  

  • Anonymous
    December 05, 2011
    How to use DbContext over existing ObjectContext? I can't find an example anywhere. Thanks!

  • Anonymous
    January 24, 2012
    @Michael: Most examples that use DbContext with MVC use context per request—for example, see msdn.microsoft.com/.../gg685467 @Suresh: You can create an IDbConnectionFactory implementation that will take your connection string and create the appropriate provider-specific DbConnection object from it. You can then set this using Database.DefaultConnectionFactory. @Shimmy: Unlike CreateObjectSet you can call Set with a derived entity type and it will return the equivalent of the OfType expression you posted. Not that internally there is still only one “entity set”. @Mehrdadc48: Not sure exactly what you are asking for here. If you provide more details I’ll try to help. @Balaje Sankar: You shouldn’t really need to do this. A better way would be to set Database.DefaultConnectionFactory to an instance of SqlConnectionFactory where you provide a new base connection string that points to your server. Or just set the connection string in your .config file. @Brian: It depends what your extension methods do, but if they don’t need a database, then turning off initialization with Database.SetInitializer<MyContext>(null) should work. @Mario B: Call the DbContext constructor that takes an ObjectContext instance and pass in your existing ObjectContext. Thanks, Arthur

  • Anonymous
    July 11, 2012
    After the summary why is there a link to the next chapter?

  • Anonymous
    July 29, 2012
    Please provide an example of usinf IDbSet and creating the instances yourself. What I want to do is to establish mocking of the IDbSets, probably within a mocked context. I read that the EF team included interfaces in the DbContext release to help us mock.  I found the IDbSet and got excited.  I created my own interface which includes both my T4 generated DbSets as IDbSets AND all the public features of the DbContext.  I started coding my mocks, using Moq, and the code was building.  I was dreaming of changing the tt file to help me.  But when I started running the tests they failed because the DbContext is not initialized.  The DbSets are null and cannot accept the .Add.  I think I might be close to getting this mocking approach to work. Has anyone implemented mocking with DbContext?  I would be really glad to see a post on that. Sincerely, Joe

  • Anonymous
    July 30, 2012
    @Joe Kahl – I’ve replied to these same questions on some of the other posts that you commented on. If you are still running into issues then please start up a http://stackoverflow.com/ thread and tag it with ‘entity-framework’ and ‘moq’.

  • Anonymous
    June 16, 2014
    how to connect to database using codefirst approach.actually i am new to asp.net .....i mean i created Dbcontext bt the table which i have used is not creating in database.

  • Anonymous
    June 17, 2014
    @Sadik - You'll find a bunch of getting started content on our MSDN site - msdn.microsoft.com/.../ee712907. If you have specific questions beyond that, start up a StackOverflow question with the entity-framework tag.