Using Entity Framework 6 with Multiple DB Schemas but using One DBContext
Asked Answered
N

4

55

I have an application using EF as ORM. The database used to have one schema, dbo and everything was working fine. I recently organized my tables into 4 different schemas. Some tables of one schema have dependencies on tables that reside on a different schema. All seems to be valid on the SQL side.

On the app side all db interactions through EF are not working anymore. The code compiles, the schemas are visible in the solution, the model mappings point to the right schemas, but once I try to insert a row to a table it does not work.

I have seen a few posts about using multiple schemas will require using multiple DBContexts but I would rather use one DBContext. All my schemas have the same owner dbo and I do not see a reason of using multiple DBContexts.

Does anyone know if there is a way to achieve this?

Newark answered 12/4, 2016 at 14:54 Comment(2)
Check here mehdi.me/ambient-dbcontext-in-ef6. You will manage all dbcontexts in one places.Syncretize
I want to use one dbcontext!Newark
G
64

You can map each table to its own schema by fluent mapping only. In your DbContext subtype you should override OnModelCreating (if you haven't done so already) and add statements like this:

modelBuilder.Entity<Department>()  
    .ToTable("t_Department", "school");

Entities that you don't map like this explicitly will be placed in the default dbo schema, or you can provide your own default by

modelBuilder.HasDefaultSchema("sales");

(summarized from here)

Guillory answered 12/4, 2016 at 20:48 Comment(2)
I don't know if it changed in the meantime, or I was blatantly incorrect, but it's not fluent mapping only. You can also use data annotations, [Table("t_Department", Schema = "school")].Guillory
It didn't work with MySQL.Metallist
C
38

In addition to the responce of Gert Arnold, you can also use Table attribute in your entity:

using System.ComponentModel.DataAnnotations.Schema;

[Table("t_Department", Schema = "school")]
public class Department
{
    public int Id { get; set; }

    public string Name { get; set; }
}
Clearness answered 4/2, 2017 at 8:36 Comment(0)
W
12

@GertArnold is spot on with his answer. However for pure syntactic candy you can also do this via a convention to pull the schema from the namespace of your models. We found this useful dealing with multiple schemas

modelBuilder.Types().Configure(e => {
        var schema = e.ClrType.Namespace.Split('.').Last().ToLower();
        var name = entity.ClrType.Name;
        return entity.ToTable(name, schema);
});

the above will take the final component of the namespace and use it as the schema name. This avoids the need for customising the table binding for every entity.

Wenz answered 4/2, 2017 at 9:2 Comment(1)
Could you elaborate or give a more complete example?Uncleanly
G
1

In my case, it's possibly that I use DB First to generate my EDMX file, so it doesn't invoke OnModelCreating method.

I finally remove all store:Schema="YourSchema" and Schema="YourSchema" in EDMX file, and I do it by write a bat file with powershell command as below, and execute the bat in the Projec Pre-Build Event:

powershell -Command "$varStr='store:Schema=""abcd""""'; $filePath='%~dp0SomeFolder\SomeFile.edmx'; (gc $filePath) -replace $varStr, '' | Out-File $filePath"
Gagliardi answered 7/10, 2019 at 4:13 Comment(2)
Why does the schema need to be removed? Why does it generate it this way?Orbit
store:Schema="YourSchema" will specify specific DB name, so it cannot be generally connect to other DB.Gagliardi

© 2022 - 2024 — McMap. All rights reserved.