I have seen several posts about this but have not been able to create a usable solution from the responses. Perhaps due to a lack of understanding.
The hosting provided requires that an identical code base be used on staging and production, including connection string.
How do I switch the connection string for DbContext?
I understand I can do something like this:
public FooEntities() : base("ApplicationServices") { }
But this is not dynamic - it merely sets it at runtime.
So how would I actually CHOOSE the connection string at runtime?
Yes public FooEntities() : base("ApplicationServices") { }
FooEntities inheriting from ObjectContext
You could also write
public FooEntities() : base(YourStaticMethodToGetConnectionString()) { }
Then you could pull the connection string from the web.config based on some environment setting
I'm reviewing this right now because I will dev local and then deploy to cloud. Therefore, want to dynamically switch connection strings being used by data context. My plan is to configure the needed connection strings in standard "connectionStrings" section of Web.config, and then place logic in the DbContext constructor, like:
public partial class MyApplicationDbContext : DbContext
{
public MyApplicationDbContext()
: base("name=cloud")
{
Database.Connection.ConnectionString =
ConnectionStringHelpers.GetHostBasedConnectionString();
}
// abbreviated..
}
Alternate:
public partial class MyApplicationDbContext : DbContext
{
public MyApplicationDbContext()
: base(ConnectionStringHelpers.GetHostBasedConnectionString())
{
}
// abbreviated..
}
Helper:
public class ConnectionStringHelpers
{
public static string GetHostBasedConnectionString()
{
return GetConnectionStringByName(GetHostBasedConnectiongStringName());
}
public static string GetHostBasedConnectiongStringName()
{
switch (System.Net.Dns.GetHostName())
{
case "myHostname": return "local"; // My local connection
case "ip-ABCD123": return "cloud"; // Cloud PaaS connection
default: return "cloud";
}
}
public static string GetConnectionStringByName(string name)
{
return ConfigurationManager.ConnectionStrings[name].ConnectionString;
}
}
And in my Web.config file:
<connectionStrings>
<add name="local" connectionString="..." providerName="System.Data.SqlClient" />
<add name="cloud" connectionString="..." providerName="System.Data.SqlClient" />
</connectionStrings>
Related
I'm new to design patterns.
I'm implementing a tool which can connect to different databases as user need.
this is my code structure.
in controllers I have my API calls. Below I paste post APi call for get all databases in server
#PostMapping("/allDatabases")
public List<String> getDatabases(#RequestBody DatabaseModel db)
throws IOException, SQLException {
return migrationInterface.getAllDatabases(db);
}
for now I'm getting response by calling a method in interface inside service package.
But when database server is change(ex: postgres,mysql) I have to use different queries.
Ex:
public class PostgresPreparedStatements {
public PreparedStatement getAllDbs(Connection con) throws SQLException {
return con.prepareStatement(
"SELECT datname FROM pg_database
WHERE datistemplate = false;");
}
}
This query is not working in MySQL database. So I'll keep deferent prepared statements for deferent databases. My idea is calling to a BaseAdapter from controller and check server type like below.
public class BaseAdapter {
public void checkServerType(String server) {
switch(server) {
case "postgres" :
// postgres functions
break;
case "mysql" :
// mysql functions
break;
default:
break;
}
}
}
I want to call PostgresConnector.java if server is postgres. from Connector I want to call Facade to call functions and related queries.
Any idea how to do this?
please note: For now I'm implementing this for postgres and MySQL,but in future this should work with any database.
Adapter pattern is not used when you want to add new behaviour such as new databases in your case. The goal of adapter class is to allow other class to access the existing functionality. Adapter converts the interface of one class into something that may be used by another class.
It looks like BaseAdapter has a responsibility to choose SQL statement for different databases. We can paraphraze this responsibility like we want to have generated SQL query based on database. So it looks like
we can replace this switch statement with HashTable(Java) or Dictionary(C#). And this HashTable(Java) or Dictionary(C#) can be a simple factory that creates SQL queries. And our generated SQL queries can be strategies for concrete database.
So let's dive in code.
It looks like this is a place where Strategy pattern can be used:
Strategy pattern is a behavioral software design pattern that enables
selecting an algorithm at runtime. Instead of implementing a single
algorithm directly, code receives run-time instructions as to which in
a family of algorithms to use.
Let me show an example via C#. I am sorry I am not Java guy, however I provided comments about how code could look in Java.
We need to have some common behaviour that will be shared across all strategies. In our case, it would be just one GetAllDbs() method from different data providers:
public interface IDatabaseStatement
{
IEnumerable<string> GetAllDbs();
}
And its concrete implementations. These are exchangeable strategies:
public class PostgresDatabaseStatement : IDatabaseStatement // implements in Java
{
public IEnumerable<string> GetAllDbs()
{
return new [] { "PostgresDatabaseStatement" };
}
}
public class MySQLDatabaseStatement : IDatabaseStatement // implements in Java
{
public IEnumerable<string> GetAllDbs()
{
return new[] { "MySQLDatabaseStatement" };
}
}
public class SqlServerDatabaseStatement : IDatabaseStatement // implements in Java
{
public IEnumerable<string> GetAllDbs()
{
return new[] { "SqlServerDatabaseStatement" };
}
}
We need a place where all strategies can be stored. And we should be able to get necessary strategy from this store. So this is a place where simple factory can be used. Simple factory is not Factory method pattern and not Abstract factory.
public enum DatabaseName
{
SqlServer, Postgres, MySql
}
public class DatabaseStatementFactory
{
private Dictionary<DatabaseName, IDatabaseStatement> _statementByDatabaseName
= new Dictionary<DatabaseName, IDatabaseStatement>()
{
{ DatabaseName.SqlServer, new SqlServerDatabaseStatement() },
{ DatabaseName.Postgres, new PostgresDatabaseStatement() },
{ DatabaseName.MySql, new MySQLDatabaseStatement() },
};
public IDatabaseStatement GetInstanceByType(DatabaseName databaseName) =>
_statementByDatabaseName[databaseName];
}
and then you can get instance of desired storage easier:
DatabaseStatementFactory databaseStatementFactory = new();
IDatabaseStatement databaseStatement = databaseStatementFactory
.GetInstanceByType(DatabaseName.MySql);
IEnumerable<string> allDatabases = databaseStatement.GetAllDbs(); // OUTPUT:
// MySQLDatabaseStatement
This design is compliant with the open/closed principle.
I've defined a project in visual studio 2015, I've used ADO NET Code first to connect with a mysql database (mysql connector 6.9.9), and now, having the model, I'm trying to use entity framework 6.
I've installed from nuget 'mysql entity framework 6.9.9' in my project, but when I try to connect with the model, next message is shown:
SBYTE THERE IS NO STORE TYPE Corresponding to the conceptual side type
'SBYTE' of primitive type 'SBYTE'
.Net framework 4.5.2
Any suggest??
Thanks!!
SByte is not a data type supported by the providers (at least is not supported by SQL Server, SQL Server CE, Microsoft Access, MySQL).
If you Really Want a class with an SByte, the best way is to use a [private] backing and expose the SByte property.
This is the model for a private backing field.
public class Info
{
public int Id { get; set; }
[MaxLength(50)]
public string Description { get; set; }
public sbyte SByte
{
get
{
return (sbyte) SByteBackingField;
}
set
{
SByteBackingField = value;
}
}
private int SByteBackingField { get; set; }
public class InfoMap : EntityTypeConfiguration<Info>
{
public InfoMap()
{
ToTable("Infoes69");
Property(_ => _.SByteBackingField).HasColumnName("SByte");
Ignore(_ => _.SByte);
}
}
}
and in context you need to add the configuration
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new Info.InfoMap());
}
The issue is that you can't use SByte property in queries.
I experienced this when using MySQL because EntityFramework defaults to using SQL Server - which does not have this data type.
The solution (for me) had 2 parts, either of which caused the same error:
Go into Web.Config, and set the correct provider for entity framework
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6, Version=6.10.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</providers>
Make sure that the connection string was set properly.
YMMV!
I have the following dependency chain:
IUserAppService
IUserDomainService
IUserRepository
IUserDataContext - UserDataContextImpl(string conn)
All interfaces above and implementations are registered in a Windsor Castle container. When I use one connection string, everything works fine.
Now we want to support multiple databases, In UserAppServiceImpl.cs, we want to get different IUserRepository (different IUserDatabaseContext) according to userId as below:
// UserAppServiceImpl.cs
public UserInfo GetUserInfo(long userId)
{
var connStr = userId % 2 == 0 ? "conn1" : "conn2";
//var repo = container.Resolve<IUserRepository>(....)
}
How can I pass the argument connStr to UserDataContextImpl?
Since the connection string is runtime data in your case, it should not be injected directly into the constructor of your components, as explained here. Since however the connection string is contextual data, it would be awkward to pass it along all public methods in your object graph.
Instead, you should hide it behind an abstraction that allows you to retrieve the proper value for the current request. For instance:
public interface ISqlConnectionFactory
{
SqlConnection Open();
}
An implementation of the ISqlConnectionFactory itself could depend on a dependency that allows retrieving the current user id:
public interface IUserContext
{
int UserId { get; }
}
Such connection factory might therefore look like this:
public class SqlConnectionFactory : ISqlConnectionFactory
{
private readonly IUserContext userContext;
private readonly string con1;
private readonly string con2;
public SqlConnectionFactory(IUserContext userContext,
string con1, string con2) {
...
}
public SqlConnection Open() {
var connStr = userContext.UserId % 2 == 0 ? "conn1" : "conn2";
var con = new SqlConnection(connStr);
con.Open();
return con;
}
}
This leaves us with an IUserContext implementation. Such implementation will depend on the type of application we are building. For ASP.NET it might look like this:
public class AspNetUserContext : IUserContext
{
public string UserId => int.Parse(HttpContext.Current.Session["UserId"]);
}
You have to start from the beginning of your dependency resolver and resolve all of your derived dependencies to a "named" resolution.
Github code link:https://github.com/castleproject/Windsor/blob/master/docs/inline-dependencies.md
Example:
I have my IDataContext for MSSQL and another for MySQL.
This example is in Unity, but I am sure Windsor can do this.
container.RegisterType(Of IDataContextAsync, dbEntities)("db", New InjectionConstructor())
container.RegisterType(Of IUnitOfWorkAsync, UnitOfWork)("UnitOfWork", New InjectionConstructor(New ResolvedParameter(Of IDataContextAsync)("db")))
'Exceptions example
container.RegisterType(Of IRepositoryAsync(Of Exception), Repository(Of Exception))("iExceptionRepository",
New InjectionConstructor(New ResolvedParameter(Of IDataContextAsync)("db"),
New ResolvedParameter(Of IUnitOfWorkAsync)("UnitOfWork")))
sql container
container.RegisterType(Of IDataContextAsync, DataMart)(New HierarchicalLifetimeManager)
container.RegisterType(Of IUnitOfWorkAsync, UnitOfWork)(New HierarchicalLifetimeManager)
'brands
container.RegisterType(Of IRepositoryAsync(Of Brand), Repository(Of Brand))
controller code:
No changes required at the controller level.
results:
I can now have my MSSQL context do its work and MySQL do its work without any developer having to understand my container configuration. The developer simply consumes the correct service and everything is implemented.
I want to load all settings key value pair from json file at once and use the settings key value in mvc 6 view page where required.I would be grateful if best solution is provided.I have a scenerio as below
if(Settings.enable_logo_text)
{
<span>Settings.logo_text</span>
}
The official documentation regarding the new configuration and options is quite good, I would recommend having a look there first.
Following the guidance provided there, start by creating a POCO class for your settings:
public class Settings
{
public string logo_text { get; set; }
public bool enable_logo_text { get; set; }
}
Update the ConfigureServices method of your startup class so you read your settings from the configured Configuration and is then available as a service that can be injected wherever you need to:
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<Settings>(Configuration);
services.AddOptions();
}
If you want to use a the appsettings.json file, make sure you also build your Configuration object including that json file. For example:
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
This way you can configure your values in the appsettings.json file and the values will be set on your Settings class:
{
...
"enable_logo_text": true,
"logo_text": "My Logo Text"
}
Finally, you can access the configured values by adding a IOptions<Settings> dependency. The most straightforward way would be to directly inject the options into the view (as explained in the docs), but you might want to consider injecting the options into the controller and passing them to the view in a more controlled way:
#inject IOptions<Settings> Settings
...
#if(Settings.Value.enable_logo_text)
{
<span>#Settings.Value.logo_text</span>
}
Using Spring Data REST with JPA in version 2.1.0.
How can I configure the pagination in order to have the page argument starting at index 1 instead of 0 ?
I have tried setting a custom HateoasPageableHandlerMethodArgumentResolver with an mvc:argument-resolvers, but that doesn't work:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.data.web.HateoasPageableHandlerMethodArgumentResolver">
<property name="oneIndexedParameters" value="true"/>
</bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>
Note that this behaviour is perfectly coherent with the documentation for mvc:argument-resolver that says:
Using this option does not override the built-in support for
resolving handler method arguments. To customize the built-in support
for argument resolution configure RequestMappingHandlerAdapter
directly.
But how can I achieve this ? If possible, in a clean and elegant way ?
The easiest way to do so is to subclass RepositoryRestMvcConfiguration and include your class into your configuration:
class CustomRestMvcConfiguration extends RepositoryRestMvcConfiguration {
#Override
#Bean
public HateoasPageableHandlerMethodArgumentResolver pageableResolver() {
HateoasPageableHandlerMethodArgumentResolver resolver = super.pageableResolver();
resolver.setOneIndexedParameters(true);
return resolver;
}
}
In your XML configuration, replace:
<bean class="….RepositoryRestMvcConfiguration" />
with
<bean class="….CustomRestMvcConfiguration" />
or import the custom class instead of the standard one in your JavaConfig file.
I have configured the RequestMappingHandlerAdapter using a BeanPostProcessor, however I believe that's neither clean, nor elegant. That looks more like a hack. There must be a better way ! I'm giving the code below just for reference.
public class RequestMappingHandlerAdapterCustomizer implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter)bean;
List<HandlerMethodArgumentResolver> customArgumentResolvers = adapter.getCustomArgumentResolvers();
if(customArgumentResolvers != null) {
for(HandlerMethodArgumentResolver customArgumentResolver : customArgumentResolvers) {
if(customArgumentResolver instanceof HateoasPageableHandlerMethodArgumentResolver) {
HateoasPageableHandlerMethodArgumentResolver hateoasPageableHandlerMethodArgumentResolver = (HateoasPageableHandlerMethodArgumentResolver)customArgumentResolver;
hateoasPageableHandlerMethodArgumentResolver.setOneIndexedParameters(true);
}
}
}
}
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
}
<beans ...>
<bean class="util.spring.beanpostprocessors.RequestMappingHandlerAdapterCustomizer" />
</beans>
I use to do it using a customizer, which is something that they keep adding for more and more components with every new version:
#Bean
public PageableHandlerMethodArgumentResolverCustomizer pageableResolverCustomizer() {
return resolver -> resolver.setOneIndexedParameters(true);
}
You can put this in any #Configuration class, but ideally you should put it (with any other customization) in one that implements RepositoryRestConfigurer.