How to: Use Multiple Models With Separate MetadataContainer Instances And The Same Connection String
This article is relevant to entity models that utilize the deprecated Visual Studio integration of Telerik Data Access. The current documentation of the Data Access framework is available here.
This article will demonstrate to you the ways to control the aggregation of the metadata for multiple models that use the same connection string. With them you can also resolve the metadata conflict that occurs when multiple models are not in the same namespace. Telerik Data Access will notify you about this with the help of MetadataException with text:
Failed to obtain a Database object. There is already opened context with the same ConnectionName/ConnectionString and its metadata is not compatible with the current one. See the inner exception for more details.
It can be resolved through providing a custom cache key that will uniquely differentiate the two models disregarding the fact that they both use one and the same connection string. The cache key can be provided in one of the following ways:
- Override The Init() Method Of The Context
- Override The CacheKey Property Of The Context
- Modify Fluent Context
The number and the type of the models in the data access layer of the application may vary according to your needs. All the solutions suggested in this article are applicable for fluent models and the first two of them are applicable for domain models as well.
Override The Init() Method Of The Context
With this approach, you will override the Init() method of the OpenAccessContextBase class in a partial class directly providing a value for the cache key. You can use it for both domain and fluent (generated and manually written) models (Sample 1: Override The Init() Method Of The Context).
Sample 1: Override The Init() Method Of The Context
using Telerik.OpenAccess;
namespace MultipleModels
{
public partial class EntitiesModel
{
protected override void Init(string connectionString, string cacheKey,
BackendConfiguration backendConfiguration,
Telerik.OpenAccess.Metadata.MetadataContainer metadataContainer,
System.Reflection.Assembly callingAssembly)
{
cacheKey = "my cache key";
base.Init(connectionString, cacheKey, backendConfiguration,
metadataContainer, callingAssembly);
}
}
}
Imports Telerik.OpenAccess
Namespace MultipleModels
Partial Public Class EntitiesModel
Protected Overrides Sub Init(ByVal connectionString As String,
ByVal cacheKey As String,
ByVal backendConfiguration As BackendConfiguration,
ByVal metadataContainer As Telerik.OpenAccess.Metadata.MetadataContainer,
ByVal callingAssembly As System.Reflection.Assembly)
cacheKey = "my cache key"
MyBase.Init(connectionString, cacheKey, backendConfiguration,
metadataContainer, callingAssembly)
End Sub
End Class
End Namespace
This code will be executed once when the first instance of the context is created, during the initialization of the metadata.
The implementation process according to the given example would be as follows:
- Add a new class to the project that holds the domain model called <context_name>.partial.cs (<context_name>.partial.vb). For example: EntitiesModel.partial.cs (EntitiesModels.partial.vb).
- Make sure that the name of the newly created class, and its definition, and its namespace match exactly those of the generated context class.
- In the newly created class, override the Init() method assigning the cacheKey parameter with a value of your own choice (here you can apply some custom computed logic).
- Save the file.
Override The CacheKey Property Of The Context
With this approach, you will override the CacheKey property of the OpenAccessContextBase class in a partial class directly providing a value for it. You can use it for both domain and fluent (generated and manually written) models (Sample 2: Override The CacheKey Property Of The Context).
Sample 2: Override The CacheKey Property Of The Context
using Telerik.OpenAccess;
namespace MultipleModels
{
public partial class EntitiesModel
{
protected override string CacheKey
{
get
{
return "my cache key";
}
}
}
}
Imports Telerik.OpenAccess
Namespace MultipleModels
Partial Public Class EntitiesModel
Protected Overrides ReadOnly Property CacheKey() As String
Get
Return "my cache key"
End Get
End Property
End Class
End Namespace
This code will be executed once when the first instance of the context is created, during the initialization of the database object.
The implementation process according to the given example would be as follows:
- Add a new class to the project that holds the domain model called <context_name>.partial.cs (<context_name>.partial.vb). For example: EntitiesModel.partial.cs (EntitiesModels.partial.vb).
- Make sure that the name of the newly created class, and its definition, and its namespace match exactly those of the generated context class.
- In the newly created class, override the CacheKey property so that it returns a value of your own choice (here you can apply some custom computed logic).
- Save the file.
Modify Fluent Context
With this approach, you will add a private field to the fluent context class so that a specific cache key is provided to the OpenAccessContext / OpenAccessContextBase constructors. It is applicable for generated fluent context classes, and manually written context types, and when you use directly the OpenAccessContext class without defining a new derived one (Sample 3: Passing A Cache Key to The Context Constructors).
Sample 3: Passing a Cache Key to The Context Constructors
private static string cacheKey = "my cache key";
public FluentModel()
:base(connectionStringName, cacheKey, backend, metadataSource)
{ }
Private Shared cacheKey As String = "my cache key"
Public Sub New()
MyBase.New(connectionStringName, cacheKey, backend, metadataSource)
End Sub
The implementation process according to the given example would be as follows:
- Open the FluentModel.cs (FluentModel.vb) file.
-
Add a new private static string field to the FluentModel class called cacheKey and assign it with a value of your own choice (Sample 4: The cacheKey Field):
private static string cacheKey = "my cache key";
Private Shared cacheKey As String = "my cache key"
-
Modify the default FluentModel constructor the way that it takes an additional parameter (Sample 5: Modify FluentModel Constructor).
Sample 5: Modify FluentModel Constructor
public FluentModel() :base(connectionStringName, cacheKey, backend, metadataSource) { }
Public Sub New() MyBase.New(connectionStringName, cacheKey, backend, metadataSource) End Sub
Save the file.