MVC 6 EF7 RC1 creating multiple dbcontexts

后端 未结 1 1702
终归单人心
终归单人心 2020-12-03 16:04

I am trying to figure out how to create a second DB context in EF7 RC1. In the past I could use a constructor with :base(\"connectionName\") but that no longer seems an opt

相关标签:
1条回答
  • 2020-12-03 17:04

    First of all I would recommend you the article from the wiki of EntityFramework on GitHub. The article describes many ways to define DbContext, which references to a section of appsettings.json. I personally prefer the way with the usage of [FromServices] attribute.

    The code could be about the following:

    First of all you defined appsettings.json with the following content

    {
      "Data": {
        "ApplicationDbConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ApplicationDb;Trusted_Connection=True;MultipleActiveResultSets=true",
        "DecAppDbConnectionString": "Server=Server=(localdb)\\mssqllocaldb;Database=DecAppDb;Trusted_Connection=True;MultipleActiveResultSets=true"
      }
    }
    

    where you define two connection strings.

    Seconds you declare the classes DecAppContext and ApplicationDbContext which have DbContext as the base class. The simplest form will be just

    public class ApplicationDbContext : DbContext
    {
    }
    public class DecAppContext : DbContext
    {
    }
    

    without any DbSet properties.

    Third Step. You use Microsoft.Extensions.DependencyInjection to inject the database contexts. To do this you need just include in Startup.cs something like

    public class Startup
    {
        // property for holding configuration
        public IConfigurationRoot Configuration { get; set; }
    
        public Startup(IHostingEnvironment env)
        {
            // Set up configuration sources.
            var builder = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json")
                .AddEnvironmentVariables();
            // save the configuration in Configuration property
            Configuration = builder.Build();
        }
    
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc()
                .AddJsonOptions(options => {
                    options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                });
            services.AddEntityFramework()
                .AddSqlServer()
                .AddDbContext<ApplicationDbContext>(options => {
                    options.UseSqlServer(Configuration["Data:ApplicationDbConnectionString"]);
                })
                .AddDbContext<DecAppContext>(options => {
                    options.UseSqlServer(Configuration["Data:DecAppDbConnectionString"]);
                });
        }
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            ...
        }
    }
    

    Se create two DbContext (DecAppContext and ApplicationDbContext) using the configuration "Data:DecAppDbConnectionString" and "Data:ApplicationDbConnectionString".

    Now we can just use the context in the controller. For example

    [Route("api/[controller]")]
    public class UsersController : Controller
    {
        [FromServices]
        public ApplicationDbContext ApplicationDbContext { get; set; }
    
        [FromServices]
        public DecAppContext DecAppContext { get; set; }
    
        [HttpGet]
        public IEnumerable<object> Get() {
            var returnObject = new List<dynamic>();
    
            using (var cmd = ApplicationDbContext.Database.GetDbConnection().CreateCommand()) {
                cmd.CommandText = "SELECT Id, FirstName FROM dbo.Users";
                if (cmd.Connection.State != ConnectionState.Open)
                    cmd.Connection.Open();
    
                var retObject = new List<dynamic>();
                using (var dataReader = cmd.ExecuteReader())
                {
                    while (dataReader.Read())
                    {
                        var dataRow = new ExpandoObject() as IDictionary<string, object>;
                        for (var iFiled = 0; iFiled < dataReader.FieldCount; iFiled++)
                            dataRow.Add(
                                dataReader.GetName(iFiled),
                                dataReader.IsDBNull(iFiled) ? null : dataReader[iFiled] // use null instead of {}
                            );
    
                        retObject.Add((ExpandoObject)dataRow);
                    }
                }
                return retObject;
            }
        }
    }
    

    or the same using async/await:

    [Route("api/[controller]")]
    public class UsersController : Controller
    {
        [FromServices]
        public ApplicationDbContext ApplicationDbContext { get; set; }
    
        [FromServices]
        public DecAppContext DecAppContext { get; set; }
    
        [HttpGet]
        public async IEnumerable<object> Get() {
            var returnObject = new List<dynamic>();
    
            using (var cmd = ApplicationDbContext.Database.GetDbConnection().CreateCommand()) {
                cmd.CommandText = "SELECT Id, FirstName FROM dbo.Users";
                if (cmd.Connection.State != ConnectionState.Open)
                    cmd.Connection.Open();
    
                var retObject = new List<dynamic>();
                using (var dataReader = await cmd.ExecuteReaderAsync())
                {
                    while (await dataReader.ReadAsync())
                    {
                        var dataRow = new ExpandoObject() as IDictionary<string, object>;
                        for (var iFiled = 0; iFiled < dataReader.FieldCount; iFiled++)
                            dataRow.Add(dataReader.GetName(iFiled), dataReader[iFiled]);
    
                        retObject.Add((ExpandoObject)dataRow);
                    }
                }
                return retObject;
            }
        }
    }
    

    One can just declare the property public ApplicationDbContext ApplicationDbContext { get; set; } with the attribute [FromServices] and ASP.NET initialize it from the context injected in ConfigureServices. In the same way one can use the second context DecAppContext whenever you need it.

    The above code example will execute SELECT Id, FirstName From dbo.Users in the database context and return JSON data in the form [{"id":123, "firstName":"Oleg"},{"id":456, "firstName":"Xaxum"}]. The conversion of property names from Id and FirstName to id and firstName will be done automatically during serialization because of usage AddJsonOptions in ConfigureServices.

    UPDATE: I have to reference the announcement. The next version of MVC (RC2) will require to change the above code to use [FromServices] as additional parameter (of method Get() for example) instead of usage public property [FromServices] public ApplicationDbContext ApplicationDbContext { get; set; }. One will need to remove the property ApplicationDbContext and to add additional parameter to Get() method: public async IEnumerable<object> Get([FromServices] ApplicationDbContext applicationDbContext) {...}. Such changes can be easy done. See here and example of the changes in the demo example of MVC:

    [Route("api/[controller]")]
    public class UsersController : Controller
    {
        [HttpGet]
        public async IEnumerable<object> Get(
                         [FromServices] ApplicationDbContext applicationDbContext,
                         [FromServices] DecAppContext decAppContext)
        {
            var returnObject = new List<dynamic>();
    
            // ...  the same code as before, but using applicationDbContext 
            // and decAppContext parameters instead of ApplicationDbContext
            // and DecAppContext properties
        }
    
    0 讨论(0)
提交回复
热议问题