It is not rare to have a scenario where a secondary database is needed to act as a backup of the primary one. This database can be a local one or hosted on another server, possibly with different backend. Due to various conditions your application may have to access this secondary database. What do you do in such case, should you have two models in your application? Certainly you can, but Telerik Data Access allows you to work with databases having the same schema on different backends using one and the same model.

In this blog post I will show you how to configure a single Fluent Model in order to connect to a database with the same schema on both Microsoft SQL Server and SQLite. There are two main steps you must take in order to do this:

  1. Map the model to the database independently from the backends.
  2. Enable the context instances creation for both SQL Server and SQLite.

Backend Independent Type Mapping

This is the key step when configuring the model to work with both SQL Server and SQLite. Backend independent type mapping can be achieved by using the WithOpenAccessType method when mapping the persistent properties of your classes to database columns. For example, consider a class User which has a decimal property Income. This property can be mapped to column independently from the backend with the following code snippet:

userMappingConfig.HasProperty(usr => usr.Income).WithOpenAccessType(OpenAccessType.Decimal)
.ToColumn("Income").HasPrecision(12).HasScale(2);

When the OpenAccessType is set using this method, Telerik Data Access will automatically determine the SQL type of the respective database column depending on the backend currently used by the model. This will decouple your mapping configuration from the backend.

Creating a Context Instance for SQL Server and SQLite

To create an instance of the context for a specific backend, we must provide it with the name of the connection string which will be used and a BackendConfiguration object with a specific setup.

A custom constructor that accepts these parameters will be needed in the context class (the one that inherits from OpenAccessContext) of the model. For convenience I will also add an additional parameter along with the respective field and property to denote the mode in which the context instance is working - Online or Offline:

public FluentModel(String connectionStringName, BackendConfiguration backendConfiguration, ContextMode contextMode)
    : base(connectionStringName, backendConfiguration, metadataSource)
{
    this.mode = contextMode;
}

private ContextMode mode;
public ContextMode Mode
{
    get
    {
        return this.mode;
    }
}

For the Mode property and its field I am using enumeration ContextMode with the following definition:

public enum ContextMode
{
    OnlineMode = 1,
    OfflineMode = 2
}

To avoid the chore of always manually initializing the context with the specific parameters for SQL Server and SQLite, you can do so in one central place - a factory class. In this specific implementation, the GetContext method will determine which backend should be used for the returned context instance based on the set ContextMode of the ContextFactoryClass.

public class ContextFactory
{
    private const string ONLINE_STORAGE_CONNECTION_NAME = @"SQLServerConnection";
    private const string OFFLINE_STORAGE_CONNECTION_NAME = @"SQLiteConnection";
    private static BackendConfiguration onlineBackendConfig;
    private static BackendConfiguration offlineBackendConfig;
    private static ContextFactory factoryInstance = null;
    private ContextMode contextMode = ContextMode.OnlineMode;

    public static ContextFactory FactoryInstance
    {
        get
        {
            if (factoryInstance == null)
            {
                onlineBackendConfig = new BackendConfiguration();
                onlineBackendConfig.Backend = "MsSql";
                onlineBackendConfig.ProviderName = "System.Data.SqlClient";
                offlineBackendConfig = new BackendConfiguration();
                offlineBackendConfig.Backend = "SQLite";
                offlineBackendConfig.ProviderName = "System.Data.SQLite";
                factoryInstance = new ContextFactory();
            }
            return factoryInstance;
        }
    }

    public ContextMode ContextMode
    {
        get
        {
            return this.contextMode;
        }
    }

    private ContextFactory()
    {
    }

    public FluentModel GetContext()
    {
        FluentModel context = null;
        if (this.contextMode == ContextMode.OnlineMode)
        {
            context = new FluentModel(ONLINE_STORAGE_CONNECTION_NAME, onlineBackendConfig, this.contextMode);
        }
        else
        {
            context = new FluentModel(OFFLINE_STORAGE_CONNECTION_NAME, offlineBackendConfig, this.contextMode);
        }
        return context;
    }

    public void SetContextMode(ContextMode contextMode)
    {
        this.contextMode = contextMode;
    }
}

Here you can find a complete demo application illustrating how to configure and use a single model to work with a database on SQL Server and SQLite. 

Now you are ready to handle scenarios where you need to access a single database on different backends from your Telerik Data Access application. Stay tuned as we will continue posting useful technical advises for your data access scenarios. 

Download Data Access


About the Author

Kristian Nikolov

Kristian Nikolov is Support Officer.

Comments

Comments are disabled in preview mode.