none
Entity Framework 4.1x Code First RRS feed

  • Question

  • Hi folks,
    Does anyone know whether it is possible to use more than one DbContext within
    Entity Framework 4.1x using the Code First approach.
    The background of this question is that the project consists of a significant number
    of classes within the model and in the next step to tables within a datastore. So, if
    we talk to separation of concerns splitting a large project into it's parts would be use-
    useful, right? DataBase.SetInitializer(  new CreateDatabaseBlahBlahBlah<MyDbContext>() )
    won't be suitable here... Right too? Are you seriously using a DbContext with 100 IDbSet
    members? If so, good to know that that's the way to do....
    How do you manage bigger projects with a Code First approach and Entity Framework 4.x?
    Thank you in advance Günther,
    a convinced and passionated Microsofty!

    qhaut
    Wednesday, November 2, 2011 4:57 PM

Answers

  • Hi,

    yes this is possible. You are talking about "bigger projects". Then i think you should implement EF with Generic Repository, DatabaseFactory and UnitOfWork Pattern. I use this approach in my project and I could add several dbcontexts, but i dont need it, because its just a class with the DBSet Properties. Every Entity has a IRepository<DbSetType> that gets the DBContext (DatabaseFactory) injected by DI and fetches the dbset from the context property using DataContext.Set<TEntity>() method.

    Here is another similiar discussion that should help you out.

    http://stackoverflow.com/questions/6654355/multiple-dbcontexts-in-n-tier-application

    HTH

    Holger

    Wednesday, November 2, 2011 7:44 PM
  • Hi,

    for development cycles I use RecreateIfModelChanges initializer. This makes development really fast. Sure. This doent work anymore after you went productive. So i make changes manually with management studio / T-SQL and deploy the generated sql scripts. I will try EF migrations soon. For now the manual way is fine for my purposes.

    http://blogs.msdn.com/b/adonet/archive/2011/09/21/code-first-migrations-alpha-3-no-magic-walkthrough.aspx

    http://blogs.msdn.com/b/adonet/archive/2011/09/21/code-first-migrations-alpha-3-with-magic-walkthrough-automatic-migrations.aspx

    Greets,

    Holger

    Sunday, November 6, 2011 11:35 AM
  • Hi,

    i try to give an example. One thing I have forgotten. If you are using DropCreateDatabaseIfModelChanges you cant use the same database, because booth DbContexts would use the same EdmMetadata.

    If you want to split your context and use DropCreateDatabaseIfModelChanges you must use different databases.

    Here is an example console app, that uses two databases, two contexts. The only thing to remind is to call Database.Initialize for all of your DbContexts, because SetInitializer would be overwritten..

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.Entity;
    
    namespace MultipleDbContexts
    {
        using System.Data.Entity;
    
        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    
        public class Log
        {
            public int Id { get; set; }
            public string Entry { get; set; }
        }
    
        public class UserContext : DbContext
        {
            public DbSet<User> Users { get; set; }
        }
    
        public class LogContext : DbContext
        {
            public DbSet<Log> Logs { get; set; }
        }
    
        public class UserContextInitalizer : DropCreateDatabaseIfModelChanges<UserContext>
        {
            protected override void Seed(UserContext context)
            {
                Console.WriteLine("UserContext seeding..");
    
                /*custom init stuff goes here*/
                context.Users.Add(new User() { Name = "Holger" });
                context.Users.Add(new User() { Name = "Günther" });
            }
        }
    
        public class LogContextInitalizer : DropCreateDatabaseIfModelChanges<LogContext>
        {
            protected override void Seed(LogContext context)
            {
                Console.WriteLine("LogContext seeding..");
    
                /*custom init stuff goes here*/
                context.Logs.Add(new Log() { Entry = "Testentry 1." });
                context.Logs.Add(new Log() { Entry = "Testentry 2." });
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Database.SetInitializer(new LogContextInitalizer());
    
                //run initialize manually, because we have multiple dbContexts
                using (var context = new LogContext())
                {
                    context.Database.Initialize(false);
                }
    
                Database.SetInitializer(new UserContextInitalizer());
    
                //run initialize manually, because we have multiple dbContexts
                using (var context = new UserContext())
                {
                    context.Database.Initialize(false);
                }
    
                using(var context = new LogContext())
                {
                    foreach(var user in context.Logs)
                        Console.WriteLine(user.Id + ": " + user.Entry);
                }
    
                using (var context = new UserContext())
                {
                    foreach (var user in context.Users)
                        Console.WriteLine(user.Id + ": " + user.Name);
                }
    
                Console.Read();
            }
        }
    }
    
    

     


    The output for the first run (or the run after you changed the model) would be:

    UserContext seeding..
    LogContext seeding..
    1: Testentry 1.
    2: Testentry 2.
    1: Holger
    2: Günther


    If you run it again, without changing the entity model:

    1: Testentry 1.
    2: Testentry 2.
    1: Holger
    2: Günther

     

    HTH

    Holger

     

    PS: app.config

     

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <connectionStrings>
        <add name="UserContext" 
    connectionString="data source=localhost;initial catalog=TestUserDb;Integrated Security=SSPI"
    providerName="System.Data.SqlClient" /> <add name="LogContext"
    connectionString="data source=localhost;initial catalog=TestLogDb;Integrated Security=SSPI"
    providerName="System.Data.SqlClient" /> </connectionStrings> </configuration>


     



    Sunday, November 6, 2011 2:19 PM

All replies

  • Hi,

    yes this is possible. You are talking about "bigger projects". Then i think you should implement EF with Generic Repository, DatabaseFactory and UnitOfWork Pattern. I use this approach in my project and I could add several dbcontexts, but i dont need it, because its just a class with the DBSet Properties. Every Entity has a IRepository<DbSetType> that gets the DBContext (DatabaseFactory) injected by DI and fetches the dbset from the context property using DataContext.Set<TEntity>() method.

    Here is another similiar discussion that should help you out.

    http://stackoverflow.com/questions/6654355/multiple-dbcontexts-in-n-tier-application

    HTH

    Holger

    Wednesday, November 2, 2011 7:44 PM
  • Hi Holger,
    Yes, I see your point. Thanks for clarification. There is one question left. What's your
    favorite way to hold your database and your model in sync? Are you using Database.SetInitializer( new Create...<YourDbContext>() )
    (which works with one DbContext only) or are you following a different approach?
    Thanks for your answer and have a great day!
    hand, günther

    Günther Schabus
    Sunday, November 6, 2011 10:20 AM
  • Hi,

    for development cycles I use RecreateIfModelChanges initializer. This makes development really fast. Sure. This doent work anymore after you went productive. So i make changes manually with management studio / T-SQL and deploy the generated sql scripts. I will try EF migrations soon. For now the manual way is fine for my purposes.

    http://blogs.msdn.com/b/adonet/archive/2011/09/21/code-first-migrations-alpha-3-no-magic-walkthrough.aspx

    http://blogs.msdn.com/b/adonet/archive/2011/09/21/code-first-migrations-alpha-3-with-magic-walkthrough-automatic-migrations.aspx

    Greets,

    Holger

    Sunday, November 6, 2011 11:35 AM
  • Hi Holger,

    Thanks again for your help. How and when do you operatively call your Database.SetInitializer with
    the mentioned RecreateIfModelChanges - Strategy? By supporting more than one DbContext Instances -
    each with a different subset of the model (UnitOfWork) - how do you manage that? I ran out of ideas
    using different DbContext Implementations (AuthorizationContext, CustomerContext and so on....) with
    this Database.SetInitializer( Strategy<DbContext> ) approach.

    Probably I am completely wrong here. Can you provide me with one line of code how do you handle
    multiple DbContext Implementations and the database update cycles.

    Thank you holger! 

     


    laugh @ your problems. everybody else does.
    Sunday, November 6, 2011 12:13 PM
  • Hi,

    i try to give an example. One thing I have forgotten. If you are using DropCreateDatabaseIfModelChanges you cant use the same database, because booth DbContexts would use the same EdmMetadata.

    If you want to split your context and use DropCreateDatabaseIfModelChanges you must use different databases.

    Here is an example console app, that uses two databases, two contexts. The only thing to remind is to call Database.Initialize for all of your DbContexts, because SetInitializer would be overwritten..

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.Entity;
    
    namespace MultipleDbContexts
    {
        using System.Data.Entity;
    
        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    
        public class Log
        {
            public int Id { get; set; }
            public string Entry { get; set; }
        }
    
        public class UserContext : DbContext
        {
            public DbSet<User> Users { get; set; }
        }
    
        public class LogContext : DbContext
        {
            public DbSet<Log> Logs { get; set; }
        }
    
        public class UserContextInitalizer : DropCreateDatabaseIfModelChanges<UserContext>
        {
            protected override void Seed(UserContext context)
            {
                Console.WriteLine("UserContext seeding..");
    
                /*custom init stuff goes here*/
                context.Users.Add(new User() { Name = "Holger" });
                context.Users.Add(new User() { Name = "Günther" });
            }
        }
    
        public class LogContextInitalizer : DropCreateDatabaseIfModelChanges<LogContext>
        {
            protected override void Seed(LogContext context)
            {
                Console.WriteLine("LogContext seeding..");
    
                /*custom init stuff goes here*/
                context.Logs.Add(new Log() { Entry = "Testentry 1." });
                context.Logs.Add(new Log() { Entry = "Testentry 2." });
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Database.SetInitializer(new LogContextInitalizer());
    
                //run initialize manually, because we have multiple dbContexts
                using (var context = new LogContext())
                {
                    context.Database.Initialize(false);
                }
    
                Database.SetInitializer(new UserContextInitalizer());
    
                //run initialize manually, because we have multiple dbContexts
                using (var context = new UserContext())
                {
                    context.Database.Initialize(false);
                }
    
                using(var context = new LogContext())
                {
                    foreach(var user in context.Logs)
                        Console.WriteLine(user.Id + ": " + user.Entry);
                }
    
                using (var context = new UserContext())
                {
                    foreach (var user in context.Users)
                        Console.WriteLine(user.Id + ": " + user.Name);
                }
    
                Console.Read();
            }
        }
    }
    
    

     


    The output for the first run (or the run after you changed the model) would be:

    UserContext seeding..
    LogContext seeding..
    1: Testentry 1.
    2: Testentry 2.
    1: Holger
    2: Günther


    If you run it again, without changing the entity model:

    1: Testentry 1.
    2: Testentry 2.
    1: Holger
    2: Günther

     

    HTH

    Holger

     

    PS: app.config

     

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <connectionStrings>
        <add name="UserContext" 
    connectionString="data source=localhost;initial catalog=TestUserDb;Integrated Security=SSPI"
    providerName="System.Data.SqlClient" /> <add name="LogContext"
    connectionString="data source=localhost;initial catalog=TestLogDb;Integrated Security=SSPI"
    providerName="System.Data.SqlClient" /> </connectionStrings> </configuration>


     



    Sunday, November 6, 2011 2:19 PM
  • Holger,

    I am truly sorry for not replying to your answer! I thought I did!

    Anyway, thank you for your efford and I reached my goal. The point

    is, that it is not possible to split DbContext-Classes within the same

    datastore.

    Following the spirit of Units of Work it's hard to maintains 100 IDbSet<TableXYZ>
    within one single DbContext. Anyway, not a big deal right now.

    Thank you, Günther

     


    laugh @ your problems. everybody else does.
    Thursday, December 1, 2011 12:16 PM
  • yw.. thanks for the feedback :)

    Greetings

    Holger

    Thursday, December 1, 2011 12:41 PM