-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support specifying catalog for table mapping #4019
Comments
Currently we only support schema and table name (and do all the appropriate escaping to deal with extra |
…(fix issue dotnet#4019) - Add database property to relational type annotations - Follow this property from explicit mapping to default query sql generator (to create proper table alias including database name) - Enhance relational model validator to including database name (this will allow have same table and schemas for different databases) - Enhance model configuration - add generator for proper toTable method if database is presented
@rowanmiller Have any plan to release this feature? our team waiting to use this feature in spring of 2017 |
@xyting it's not on our list for an upcoming release. It would make a good external contribution though 😄 |
Just to add one use case here, I currently have an application that uses 3 databases databases in the same server, and a dozen servers that access the same 3 databases. Because the connection string is different for each database, each application has 3 connection pools to the same server. This causes lots of connections being open to the same server, which can cause the server to stop accepting connections sometimes. This can be kept under control to some extent using So, I'm in line for this feature. =) |
This would also solve problems with common (shared) tables when solving multiple tenants with Separate Database for every tenant: There is currently no work around. |
Just to add another usecase. I am dealing with a legacy database that is composed of no less than 23 different databases with tons of unmaintainable legacy applications using it and querying across the different databases. Basically I am creating an OData Web API using MVC Core + EF Core to abstract the misery for future applications. The only show stopper for now is the fact that I cannot specify the catalog and expect entity framework to behave like a good boy. |
I have a modification I made to the 2.2 code that would handle this, but only for QueryTypes, because to me, this feels like the only place walking across a catalog is practical. It would be possible to add the support for entity types as well, but I feel that in that case, you would be better off having a separate context for that purpose. release/2.2...mrswain:add-catalog-support If this looks like it is a good approach I can submit a PR but I am not sure what tests may be needed or if some of my code changes are API no-nos. Edit: I also added ,following the patter, support for a default catalog thought I did not limit it to just querytypes as I was unsure at the point it is implemented, on how to do that properly. This does limit the usefullness of a default catalog property. |
This feature would be great, because single database can't handle large datasets. So many use by separating them for different tenants. in that case some tables are shared. so this feature can be a game changer. |
@Mrswain The approach seems ok to me in general. If you send a PR, we can discuss a few details there. In the meantime, here are a few things that come to mind:
|
Possible workaround: use a Proof of concept: I now make an EF model pretending that the tables in these database are actually are in the same database: public class DatabaseOne : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=DatabaseOne;ConnectRetryCount=0");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TableOne>().ToTable("TableOne", "SchemaOne");
modelBuilder.Entity<TableTwo>().ToTable("TableTwo", "SchemaTwo");
}
}
public class TableOne
{
public int Id { get; set; }
public string Foo { get; set; }
}
public class TableTwo
{
public int Id { get; set; }
public string Foo { get; set; }
} (Note this clearly won't work if both database contain tables with the same table and schema name.) Now create an interceptor-like construct using public class CommandInterceptor : IObserver<KeyValuePair<string, object>>
{
public void OnCompleted()
{
}
public void OnError(Exception error)
{
}
public void OnNext(KeyValuePair<string, object> value)
{
if (value.Key == RelationalEventId.CommandExecuting.Name)
{
var command = ((CommandEventData) value.Value).Command;
// Do command.CommandText manipulation here...
command.CommandText = command.CommandText.Replace(
"[SchemaTwo].[TableTwo]",
"[DatabaseTwo].[SchemaTwo].[TableTwo]");
}
}
}
public class EfGlobalListener : IObserver<DiagnosticListener>
{
private readonly CommandInterceptor _commandInterceptor = new CommandInterceptor();
public void OnCompleted()
{
}
public void OnError(Exception error)
{
}
public void OnNext(DiagnosticListener listener)
{
if (listener.Name == DbLoggerCategory.Name)
{
listener.Subscribe(_commandInterceptor);
}
}
} Registering and testing: public class Program
{
public static void Main()
{
DiagnosticListener.AllListeners.Subscribe(new EfGlobalListener());
using (var context = new DatabaseOne())
{
foreach (var entity in context.Set<TableOne>())
{
Console.WriteLine($"{entity.Id}: {entity.Foo}");
}
foreach (var entity in context.Set<TableTwo>())
{
Console.WriteLine($"{entity.Id}: {entity.Foo}");
}
}
}
} |
Should there is a Option for DbContext to just inlucde DatabaseName in the Query ? [DatabaseName("Db1")]
public class Db1DbContext :DbContext{}
//or
public class Db2DbContext:DbContext
{
override onModelCreate(ModelBuilder builder)
{
builder.UseDatabaseName("Db2")
}
} |
Another workaround (similar to @ajcvickers answer above and derived from this blog) - this removes hardcoding of database names: using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace MulitpleDb.Sample.Data
{
public class FooConfiguration : IEntityTypeConfiguration<FooTableClass>
{
public void Configure(EntityTypeBuilder<Planet> builder)
{
builder.ToTable("FooTable","[Database2].[dbo]");
builder.HasKey(e => e.Id);
builder.Property(a => a.Name).IsRequired();
}
}
} Interceptor Workaround classes: public class GlobalCommandInterceptor : IObserver<KeyValuePair<string, object>>
{
public void OnCompleted()
{
}
public void OnError(Exception error)
{
}
public void OnNext(KeyValuePair<string, object> value)
{
if (value.Key == RelationalEventId.CommandExecuting.Name)
{
var command = ((CommandEventData)value.Value).Command;
command.CommandText = command.CommandText.Replace(
"[[",
"[").Replace("]]]", "]").Replace("]]", "]");
}
}
}
public class GlobalListener : IObserver<DiagnosticListener>
{
private readonly GlobalCommandInterceptor _commandInterceptor = new GlobalCommandInterceptor();
public void OnCompleted()
{
}
public void OnError(Exception error)
{
}
public void OnNext(DiagnosticListener value)
{
if (value.Name == DbLoggerCategory.Name)
value.Subscribe(_commandInterceptor);
}
} and called in Startup.cs: DiagnosticListener.AllListeners.Subscribe(new GlobalListener()); |
From 2015-12 to 2021-8 , almost 6 years , anything new on this (expect drop from next version again) |
@John0King see this for how we decide what to work on. This issue has received only 5 votes since it was opened in 2015, and there is are reasonable workaround (i.e. introduce the database name directly into the SQL via a command interceptor). |
The workarounds work. However, it seems a little heavy handed. I now have to listen to, check and potentially change every query. I am not sure of the overall impact since I just tested this and it works, but, jeez. I am a little concerned. I realize that multiple databases are perhaps not very common (maybe??), I've moved our team into Azure SQL and PAAS which doesn't support cross-database queries (to get away from maintenance and administration) and I now use schemas for what we used to use databases for. I just happened to find myself in someone else's org doing work on servers that have upwards of 30 databases each and I wanted to use EF core and not start hand-writing SQL again... Food for thought, I work in a very large organization where every non-PAAS SQL database uses multiple databases. It's a culture thing in this enterprise (the Oracle databases we have do the same). They would be hard-pressed to move to EF for this alone. And they would not bother coming in here and voting for this to ensure the team sees it as important. I think most people are this way. While I know you need some way to determine what's important, somethings should just work if they work in the underlying systems (like cross-database queries). |
I need to access a Table from another database located in the same server, so I did specify its location in the table name but this do not work.
The problem are the angled brackets put in the name of the table. Can I avoid inserting this brackets into the table name?
I receive this exception:
The text was updated successfully, but these errors were encountered: