MVC 6 EF7 RC1 crea più dbcontexts

asp.net-core-mvc entity-framework-core

Domanda

Sto cercando di capire come creare un secondo contesto DB in EF7 RC1. In passato potevo usare un costruttore con: base ("connectionName") ma che non sembra più un'opzione poiché dice che non è possibile convertire la stringa in System.IServiceProvider.

Il mio secondo codice di contesto è il seguente:

public class DecAppContext : DbContext
    {

        public DecAppContext()
          //  :base("DefaultConnection")
        {

        }
        public DbSet<VignetteModels> VignetteModels { get; set; }
        public DbSet<VignetteResult> Result { get; set; }
    }
}

Nel mio config.json ho specificato la connessione:

"Data": {
    "DefaultConnection": {
      "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=aspnet5-xxxxx...;Trusted_Connection=True;MultipleActiveResultSets=true"
    }
  }

Nella mia sezione dei servizi di configurazione del mio avvio ho aggiunto entrambi i contesti:

services.AddEntityFramework()
                .AddSqlServer()
                .AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]))
                .AddDbContext<DecAppContext>(options => options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

Il contesto applicationDB funziona bene poiché posso creare un utente e accedere senza problemi

Tuttavia quando provo ad accedere all'altro contesto come nel mio controller tramite:

private DecAppContext db = new DecAppContext();
var vignette = db.VignetteModels.SingleOrDefault(v => v.CaseId == vid);

Ottengo l'errore:

Nessun provider di database è configurato. Configurare un provider di database eseguendo l'override di OnConfiguring nella classe DbContext o nel metodo AddDbContext durante l'impostazione dei servizi.

Qualsiasi esempio di lavoro in EF7 RC1 con più contesti db e accesso ad essi sarebbe molto apprezzato.

Risposta accettata

Prima di tutto ti consiglierei l'articolo dal wiki di EntityFramework su GitHub. L'articolo descrive molti modi per definire DbContext , che fa riferimento a una sezione di appsettings.json . Personalmente preferisco il modo con l'uso dell'attributo [FromServices] .

Il codice potrebbe essere il seguente:

Prima di tutto hai definito appsettings.json con il seguente contenuto

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

dove si definiscono due stringhe di connessione.

Secondi dichiari le classi DecAppContext e ApplicationDbContext che hanno DbContext come classe base. La forma più semplice sarà giusta

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

senza alcuna proprietà DbSet .

Terzo passo. Si utilizza Microsoft.Extensions.DependencyInjection per iniettare i contesti del database. Per fare ciò è sufficiente includere in Startup.cs qualcosa del genere

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 si creano due DbContext ( DecAppContext e ApplicationDbContext ) utilizzando la configurazione "Data:DecAppDbConnectionString" e "Data:ApplicationDbConnectionString" .

Ora possiamo semplicemente usare il contesto nel controller. Per esempio

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

o lo stesso usando async / attendi:

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

Si può semplicemente dichiarare la proprietà public ApplicationDbContext ApplicationDbContext { get; set; } con l'attributo [FromServices] e ASP.NET inizializzano dal contesto immesso in ConfigureServices . Allo stesso modo si può usare il secondo contesto DecAppContext ogni volta che ne hai bisogno.

L'esempio di codice precedente eseguirà SELECT Id, FirstName From dbo.Users nel contesto del database e restituirà i dati JSON nella forma [{"id":123, "firstName":"Oleg"},{"id":456, "firstName":"Xaxum"}] . La conversione dei nomi delle proprietà da Id e FirstName in id e firstName verrà eseguita automaticamente durante la serializzazione a causa dell'utilizzo di AddJsonOptions in ConfigureServices .

AGGIORNAMENTO: devo fare riferimento all'annuncio . La prossima versione di MVC (RC2) richiederà di cambiare il codice sopra per usare [FromServices] come parametro aggiuntivo (del metodo Get() per esempio) invece di [FromServices] public ApplicationDbContext ApplicationDbContext { get; set; } public property [FromServices] public ApplicationDbContext ApplicationDbContext { get; set; } . Uno dovrà rimuovere la proprietà ApplicationDbContext e aggiungere ulteriori parametri al metodo Get() : public async IEnumerable<object> Get([FromServices] ApplicationDbContext applicationDbContext) {...} . Tali cambiamenti possono essere fatti facilmente. Vedi qui ed esempio delle modifiche nell'esempio demo di 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
    }



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché