2

In my application, for performance reasons I want to replicate the database to a separate reporting-only database, and keep my transactional work on the primary database and handle updates through synchronization on the SQL Server side. Using this, I want to offload the very intensive data-heavy database operations to the reporting-only (read-only) database. The two database instances are identical in terms of schema. We are developing entity framework database-first, scaffolding the database tables into our application.

I initially set this up where the reporting context used only the reporting tables, which are table schemas created to model output from the stored procedures with which all the reports are generated. So they were distinct names from the transactional database context and everything worked great. Now, however, we've found some other data-heavy queries that we want to offload to the reporting database as well, so we need to scaffold all of the same tables from the transactional database context to the reporting database context.

Here are my two scaffolding commands:

Scaffold-DbContext "Server=SERVERNAME;Database=DBNAME;User ID=ID;Password=PW;" Microsoft.EntityFrameworkCore.SqlServer -NoOnConfiguring -OutputDir Model\DB -Context TransContext -UseDatabaseNames -f -t tablenames...

Scaffold-DbContext "Server=SERVERNAME;Database=DBNAME;User ID=ID;Password=PW;" Microsoft.EntityFrameworkCore.SqlServer -NoOnConfiguring -OutputDir Model\DB\Reporting -Context ReportsContext -UseDatabaseNames -f -t tablenames...

So the tables are scaffolded into a subfolder for the ReportsContext to allow the duplicate tables without overwriting the ones created by the first scaffolding command.

When I scaffold the same tables from the two different databases into the two contexts, I get the error "'TableName' is an ambiguous reference between AppName.Model.DB.TableName and AppName.Model.DB.Reporting.TableName" for every table. The context you use properly identifies the class/table you're referencing, but the instantiation of the table class doesn't know which copy of the table it's supposed to be referencing. I would really hate to have to fully-qualify every database model class throughout the application, is there an easier way that I'm missing?

6
  • is there an easier way that I'm missing? - scaff once and vary the conenction string used by whatever context X is being used by the code? Commented Feb 25, 2022 at 16:27
  • Is there any way in the scaffolding command to prepend an identifier onto all the generated table names? So my reporting context would now be full of tables like "RptVisit" and the other context would reference "Visit" but they'd be the same tables. Commented Feb 25, 2022 at 17:17
  • Yes, but that sounds like something you'd use a schema for instead (dbo.Visit, rpt.Visit), but why throw that hurdle in your own way? The two DB are different; why not let them have the same table names, make life easier Commented Feb 25, 2022 at 17:24
  • Can you give an example of how you'd do that, varying the connection string in the controller depending on what you're trying to do? It sure seems like a cleaner solution. The two databases are identical. Commented Feb 25, 2022 at 17:27
  • I've been trying very similar thing (in terms of having two db contextes) and got some issues that when create/update is made via write context after a short period of time (~200ms or so) changes are still not available via read context, have you faced anything similar? Commented Feb 1, 2023 at 8:12

2 Answers 2

2

If you take your DB context, make it abstract (not vital, but stops you new'ing it accidentally) and change its constructor signature:

public abstract partial class MyContext: DbContext
{
    public MyContext(DbContextOptions options): base(options) {}

And then make a couple of new do-nothing contexts that extend it and pass the options through to the base constructor:

public class ReportingMyContext: MyContext 
{
    public ReportingMyContext(DbContextOptions<ReportingMyContext> options) : base(options) { }
}

public class MainMyContext: MyContext
{
    public MainMyContext(DbContextOptions<MainMyContext> options) : base(options) { }

}

And register them with different connection strings:

services.AddDbContext<ReportingMyContext>(options =>
    options.UseSqlServer("Data Source=blah blah blah")
);

services.AddDbContext<MainMyContext>(options =>
    options.UseSqlServer("Data Source=blow blow blow")
);

Then you can get the injector to inject the different context depending on what it sees you use

class ReportsController{
  ReportsController(ReportingMyContext x){
    x.SomeTable.Count() //counts reports db
  }

class UsersController{
  UsersController(MainMyContext x){
    x.SomeTable.Count() //counts main db
  }

There are other ways of varying the connection string, but if you're familiar with and happy with the way getting a context via DI works then it can be handy and simple to just change the connected database by varying the Type of the injected context, or injecting both if you have some heavy reporting/querying need but some updates etc to make too. You might eventually start to add some things that were specific to only one context too.. A similar approach could perhaps be taken with interfaces too, though there's a bit more typing involved in specifying which members of the context are members of the interface so that when you say UsersController(IReportingDbContext x) { x.<thing> then <thing> is actually there without a cast

Other methods such as setting the connection string after you get the context are possible with later EFs..

Sign up to request clarification or add additional context in comments.

Comments

0

when you dependency inject in your controller or class the solver will bind to the correct data context. Ensure the connection strings are unique for each datacontext.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.