Skip to main content
All docs
V24.1
.NET Framework 4.5.2+

How to: Use Multiple Data Models Connected to Different Databases in Entity Framework Core

  • 4 minutes to read

This article describes how to implement an XAF application with custom Entity Framework DbContexts that work with separate databases. These modules do not depend on each other and thus can be reused in other applications independently.

View Example: How to connect different data models to several databases within a single application with Entity Framework Core

This example assumes that you have an XAF application that includes both Windows Forms and ASP.NET Core Blazor projects with standard authentication enabled and the Security System configured in Integrated Mode.

Define Separate Connection Strings

In the configuration files for the Blazor and WinForms projects, define three separate connection strings: one connection string for a database that stores security data and two additional connection strings for separate databases used to store application data.

File: SolutionName.Blazor.Server/appsettings.json, SolutionName.Win/App.config

"ConnectionStrings": {
  "ConnectionString0": "Integrated Security=SSPI;Pooling=false;MultipleActiveResultSets=true;Data Source=(localdb)\\mssqllocaldb;Initial Catalog=DB0_EFCore",
  "ConnectionString1": "Integrated Security=SSPI;Pooling=false;MultipleActiveResultSets=true;Data Source=(localdb)\\mssqllocaldb;Initial Catalog=DB1_EFCore",
  "ConnectionString2": "Integrated Security=SSPI;Pooling=false;MultipleActiveResultSets=true;Data Source=(localdb)\\mssqllocaldb;Initial Catalog=DB2_EFCore",
}

Configure the Main Module’s DbContext to Store Security Data

In the example project, the main module’s DbContext is configured to only store data used by the Security System (users, roles, and login information). The XAF Solution Wizard generates the required code if you enable the Security System. Otherwise, you need to add the required persistent classes and configure the platform specific projects as described in the following article: Use the Security System - Implement Standard Authentication in Code.

File: CommonModule/BusinessObjects/CommonModuleDbContext.cs

public class CommonModuleEFCoreDbContext : DbContext {
  // ...
  public DbSet<PermissionPolicyRole> Roles { get; set; }
  public DbSet<ApplicationUser> Users { get; set; }
  public DbSet<ApplicationUserLoginInfo> UserLoginInfos { get; set; }
  // ...
}

File: SolutionName.Blazor.Server/Startup.cs, SolutionName.Win/Startup.cs

public class Startup {
    // ...
    public void ConfigureServices(IServiceCollection services) {
        services.AddXaf(Configuration, builder => {
            builder.Security
                .UseIntegratedMode(options => {
                    options.RoleType = typeof(PermissionPolicyRole);
                    options.UserType = typeof(CommonModule.BusinessObjects.ApplicationUser);
                    options.UserLoginInfoType = typeof(CommonModule.BusinessObjects.ApplicationUserLoginInfo);
                })
            // ...
        });
    }
}

Add Custom Modules to Store Data in Separate Databases

Use the XAF Solution Wizard to add two new custom XAF modules to an XAF solution as described in the Modules article. For each custom module, implement its own DbContext and persistent classes.

Add static methods that configure the Object Space and DbContexts (SetupObjectSpace() and SetupDbContext()) to all module classes in the solution. Make sure that each module uses its own connection string.

File: ClassLibrary1/XafModule1.cs, ClassLibrary2/XafModule2.cs, CommonModule/Module.cs

using DevExpress.ExpressApp.ApplicationBuilder.Internal;
using Microsoft.Extensions.Configuration;

public class XafModule1 : ModuleBase {
    // ...
    // Specify a separate connection string for each module.
    const string ConnectionStringName = "ConnectionString1"; 

    public static void SetupObjectSpace<TContext>(IObjectSpaceProviderBuilder<TContext> objectSpaceProviderBuilder) 
        where TContext : IXafApplicationBuilder<TContext> {
        string connectionString = ConfigurationManager.ConnectionStrings[ConnectionStringName]?.ConnectionString;
        objectSpaceProviderBuilder.AddSecuredEFCore()
            .WithDbContext<ClassLibrary1EFCoreDbContext>((application, options) => 
                SetupDbContext(options, connectionString));
    }

    public static void SetupObjectSpace<TContext>(IObjectSpaceProviderServiceBasedBuilder<TContext> 
      objectSpaceProviderBuilder, IConfiguration configuration) 
        where TContext : IXafApplicationBuilder<TContext>, IAccessor<IServiceCollection> {
        string connectionString = configuration.GetConnectionString(ConnectionStringName);
        objectSpaceProviderBuilder.AddSecuredEFCore()
            .WithDbContext<ClassLibrary1EFCoreDbContext>((application, options) => 
                SetupDbContext(options, connectionString));
    }

    static void SetupDbContext(DbContextOptionsBuilder options, string connectionString) {
        ArgumentNullException.ThrowIfNull(connectionString);
        options.UseSqlServer(connectionString);
        options.UseChangeTrackingProxies();
        options.UseObjectSpaceLinkProxies();
        options.UseLazyLoadingProxies();
    }
}

Make the following edits to the Startup.cs files in your Blazor and WinForms projects:

  • Register the additional modules as shown in the code sample below:

    public void ConfigureServices(IServiceCollection services) {
        // ...
        services.AddXaf(Configuration, builder => {
            // ...
            builder.Modules 
                .Add<ClassLibrary1.XafModule1>()
                .Add<ClassLibrary2.XafModule2>();
            // ...
        }
    }
    
  • Call the SetupObjectSpace() static methods for the ClassLibrary1 and ClassLibrary2 modules. ASP.NET Core Blazor and Windows Forms projects require different overloads of this method:

    public void ConfigureServices(IServiceCollection services) {
        // ...
        services.AddXaf(Configuration, builder => {
            // ...
            ClassLibrary1.XafModule1.SetupObjectSpace(builder.ObjectSpaceProviders, Configuration);
            ClassLibrary2.XafModule2.SetupObjectSpace(builder.ObjectSpaceProviders, Configuration);
            // ...
        }
    }
    

    Note

    Business classes linked to different ObjectSpaceProviders are considered to be isolated from each other and thus cannot have direct links between them, e.g., an association between two classes. Consider using the How to prevent altering the legacy database schema when creating an XAF application or alternative solutions if you need interlinks between classes from different data stores.