We are using EF.Core for a current project. The project has three databases which is a real nuisance that can\'t really be avoided. The databases have the same structure. So we
Interesting problem.
One context cannot across multiple database,
using multiple context will end up loading data in memory and doing linq to objects which perhaps is not desired or even possible.
First option is to use linked tables in database and query against it. which I think is the easiest.
I don't know how complex is your query and how big is data to suggest a in memory scenario, based on what you are doing in your query you may have some ad hoc solutions , examples:
So the questioner (P.Joe) answers his own question here (https://stackoverflow.com/a/43326729/861352), but I can't actually get that answer to work. The reason it doesn't work is
[Table("dbname.scheme.Stock", Schema = "dbo")]
will get rendered in the sql as
[dbo].[dbname.scheme.Stock]
when what you actually want in the SQL is
[dbname].[dbo].[Stock]
Even if you try and mess around with it wont work. I tried various combinations
[Table("Stock", Schema = "dbname.dbo")] // SQL => [dbname.dbo].[Stock]
[Table("Stock", Schema = "[dbname].[dbo]")] // SQL => [[dbname]].[dbo]]].[Stock]
[Table("Stock", Schema = "dbname].[dbo")] // SQL => [dbname]].[dbo].[Stock]
[Table("Stock", Schema = "dbname.[dbo")] // SQL => [dbname.[dbo].[Stock]
...etc. The basic problem is that you need to separate the dbname with brackets that get escaped when it's parsed.
This actually appears to be a known issue, with a solution in the pipeline (although it hasn't been prioritised yet):
https://github.com/aspnet/EntityFrameworkCore/issues/4019
I did however find an interim solution to this problem, and it's based on two sources:
https://stackoverflow.com/a/26922902/861352 (EF6 solution) https://weblogs.asp.net/ricardoperes/interception-in-entity-framework-core
And here it is:
How To Do (Same Server) Cross DB Joins With One EF Core DbContext
You'll need to install the Microsoft.Extensions.DiagnosticAdapter Nuget Package
using System;
using System.Data.Common;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.DiagnosticAdapter;
namespace Example
{
public class CommandInterceptor
{
[DiagnosticName("Microsoft.EntityFrameworkCore.Database.Command.CommandExecuting")]
public void OnCommandExecuting(DbCommand command, DbCommandMethod executeMethod, Guid commandId, Guid connectionId, bool async, DateTimeOffset startTime)
{
var secondaryDatabaseName = "MyOtherDatabase";
var schemaName = "dbo";
var tableName = "Stock";
command.CommandText = command.CommandText.Replace($" [{tableName}]", $" [{schemaName}].[{tableName}]")
.Replace($" [{schemaName}].[{tableName}]", $" [{secondaryDatabaseName}].[{schemaName}].[{tableName}]");
}
}
}
Replace 'MyOtherDatabase', 'dbo' and 'Stock' with your Database name, table schema and table name, maybe from a config etc.
Then attach that interceptor to your context.
using System.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
var context = new MultipleDatabasesExampleDbContext(optionsBuilder.Options);
// Add interceptor to switch between databases
var listener = context.GetService<DiagnosticSource>();
(listener as DiagnosticListener).SubscribeWithAdapter(new CommandInterceptor());
In my case I put the above in MultipleDatabasesExampleDbContextFactory method.
Now you can just use the context as if you were referencing one database.
context.Customers // Default database defined in connection string
context.Stocks // MyOtherDatabase (a different database on the same server)
Ok, so I believe we have found a way to do cross db queries using EF Core with execution happening on the database and not in shared memory. So I shall do this with a stock system as an example. I hope it is of use to somebody.
First of all synonyms need to be created for SQLSERVER db, on the master table, so associated tables are all linked together.
Then our EF models and derived classes should be as follows.
public abstract class Stock
{
public int ID{get;set;}
public string stockName{get;set;}
}
[Table("dbname.scheme.Stock", Schema = "dbo")]
public class WinterStock : Stock
{
public WinterStock() : base() { }
}
[Table("dbname.scheme.Stock", Schema = "dbo")]
public class SummerStock : Stock
{
public SummerStock() : base() { }
}
In our test method we have...
var query = _context.Set<WinterStock>().Join(_context.Set<SummerStock>(), winterStock => winterStock.stockName,summerStock => summerStock.stockName, (summerStock,winterStock) => new { summerStock, winterStock });
var result = query.ToList();