I'm trying to connect to some databases. I'm using one class to connect to my connection string with this code:
private static BaseDados instance;
public static BaseDados Instance
{
get
{
if (instance == null)
instance = new BaseDados();
return instance;
}
}
private string strLigacao;
private MySqlConnection ligacaoBD;
public BaseDados()
{
//ligação à`enter code here` bd
strLigacao = ConfigurationManager.ConnectionStrings["empresaA"].ToString();
ligacaoBD = new MySqlConnection(strLigacao);
ligacaoBD.Open();
}
And then I'm changing the connection string with:
Configuration configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
var section = (ConnectionStringsSection)configuration.GetSection("connectionStrings");
section.ConnectionStrings["empresaB"].ConnectionString = #"Server=localhost;Database=" + DropDownList1.SelectedValue.ToString() + " ;Uid=root;Pwd=Qwerty!123;";
configuration.Save();
Response.Redirect("**********");
Well, this method only supports one database at the same time, because someone said to me this is a singleton.
Someone knows how to change this to support multiple databases?
Related
I'm creating an app that should work with various sqlite databases (with same structure) and I want to be able to open and close different databases. I use EF6 and I just can't figure out how to open a different database file (and make EF to reload and use data from new file). There are many questions regarding this but none of them work for me.
this is my dbContext generated by EF
public partial class mainEntities : DbContext
{
public mainEntities()
: base("name=mainEntities")
{
}
...
}
this is how I use and try to update my context
class Db
{
private static mainEntities myDbInstance;
public static mainEntities MyDbInstance
{
get
{
if (myDbInstance == null)
{
myDbInstance = new mainEntities();
}
return myDbInstance;
}
}
public static void UpdateConnectionString(string pth)
{
StringBuilder sb = new StringBuilder();
sb.Append("metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;");
sb.Append("provider=System.Data.SQLite.EF6;");
sb.Append("provider connection string=");
sb.Append("'");
sb.Append("datetime format=JulianDay;");
sb.Append("foreign keys=True;");
sb.Append("data source=");
sb.Append(pth);
sb.Append("'");
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var connectionStringsSection = (ConnectionStringsSection)config.GetSection("connectionStrings");
connectionStringsSection.ConnectionStrings["mainEntities"].ConnectionString = sb.ToString();
connectionStringsSection.ConnectionStrings["mainEntities"].ProviderName = "System.Data.EntityClient";
config.Save();
ConfigurationManager.RefreshSection("connectionStrings");
Properties.Settings.Default.Save();
Properties.Settings.Default.Reload();
//reset context - does not work
MyDbInstance.Dispose();
myDbInstance = null;
}
}
I am able to update the connectionString,
var conn_str = System.Configuration.ConfigurationManager.ConnectionStrings["mainEntities"].ConnectionString;
returns correct string after I change database file, but data is loaded from the original one.
EDIT:
I check if the connection changed with simple WPF GUI
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void refresh_labels()
{
var conn_str = System.Configuration.ConfigurationManager.ConnectionStrings["mainEntities"].ConnectionString;
var rows_count =
(from d in Db.MyDbInstance.TagsFiles
select d).Count();
label1.Content = conn_str.Split(';')[4];
label2.Content = rows_count;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
String DbFileName1 = #"c:\tmp\db1.db3";
String DbFileName2 = #"c:\tmp\db2.db3";
var conn_str = System.Configuration.ConfigurationManager.ConnectionStrings["mainEntities"].ConnectionString;
if (conn_str.Contains(DbFileName1))
{
Db.UpdateConnectionString(DbFileName2);
}
else
{
Db.UpdateConnectionString(DbFileName1);
}
refresh_labels();
}
}
I have a dll that uses the Entity Framework 6 to do some database operations. I'm using a database first approach.
The model and everything concerning the Entity Framework, like the connection string in the App.config, were created via the wizzard in Visual Studio.
So I compiled the dll and put it together with the corresponding .config in the folder where the application using the dll expects it.
Everything works fine until I get to the point where an actual database call is made. There I get the error:
Cannot find connection string for MyDatabaseEntity
The automatically generated connectionstring is, as I said, in the config file of the dll. I cannot change the App.config of the application.
But the application hands over an object that has all the information I need to build the connection string myself.
So I'm looking for a way to set the connection string in the code without relying on a config file.
All the tutorials I find for a database first approach use this method though.
I found a post here that says to simply give the connection string as a parameter when creating the Object like
MyDatabaseEntities = new MyDatabaseEntities(dbConnect);
but ´MyDatabaseEntities´ doesn't have a constructor that takes any parameters
public partial class MyDatabaseEntities : DbContext
{
public MyDatabaseEntities()
: base("name=MyDatabaseEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<MyTable> MyTable { get; set; }
}
How about:
public partial class MyDatabaseEntities : DbContext
{
public MyDatabaseEntities(string connectionString)
: base(connectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<MyTable> MyTable { get; set; }
}
Then initialize your database like you did before:
string myConnectionString = "...";
MyDatabaseEntities = new MyDatabaseEntities(myConnectionString);
I had the similar issue. My Edmx and App.Config was in a different project. My startup project was different, had 3 different connection strings, we need to choose one on the fly depending on the environment. So couldn't use a fixed connection string. I created a partial class overload of the Context.cs using the same namespace. Following was my default Context.cs;
namespace CW.Repository.DBModel
{
public partial class CWEntities : DbContext
{
public CWEntities()
: base("name=CWEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
...
...
}
}
My partial class overload;
namespace CW.Repository.DBModel
{
public partial class CWEntities : DbContext
{
public CWEntities(string ConnectionString)
: base(ConnectionString)
{
}
}
}
Lastly, as my connection strings were not for EF, I converted them to a EF connection string.
public static string GetEntityConnectionString(string connectionString)
{
var entityBuilder = new EntityConnectionStringBuilder();
// WARNING
// Check app config and set the appropriate DBModel
entityBuilder.Provider = "System.Data.SqlClient";
entityBuilder.ProviderConnectionString = connectionString + ";MultipleActiveResultSets=True;App=EntityFramework;";
entityBuilder.Metadata = #"res://*/DBModel.CWDB.csdl|res://*/DBModel.CWDB.ssdl|res://*/DBModel.CWDB.msl";
return entityBuilder.ToString();
}
Lastly, the calling
var Entity = new CWEntities(CWUtilities.GetEntityConnectionString(ConnectionString));
I got this solution using below code, I can hardcode connection string using C# code without using config file.
public class SingleConnection
{
private SingleConnection() { }
private static SingleConnection _ConsString = null;
private String _String = null;
public static string ConString
{
get
{
if (_ConsString == null)
{
_ConsString = new SingleConnection { _String = SingleConnection.Connect() };
return _ConsString._String;
}
else
return _ConsString._String;
}
}
public static string Connect()
{
//Build an SQL connection string
SqlConnectionStringBuilder sqlString = new SqlConnectionStringBuilder()
{
DataSource = "SIPL35\\SQL2016".ToString(), // Server name
InitialCatalog = "Join8ShopDB", //Database
UserID = "Sa", //Username
Password = "Sa123!##", //Password
};
//Build an Entity Framework connection string
EntityConnectionStringBuilder entityString = new EntityConnectionStringBuilder()
{
Provider = "System.Data.SqlClient",
Metadata = "res://*/ShopModel.csdl|res://*/ShopModel.ssdl|res://*/ShopModel.msl",
ProviderConnectionString = #"data source=SIPL35\SQL2016;initial catalog=Join8ShopDB2;user id=Sa;password=Sa123!##;"// sqlString.ToString()
};
return entityString.ConnectionString;
}
and using DbContext using like this:
Join8ShopDBEntities dbContext = new Join8ShopDBEntities(SingleConnection.ConString);
Thanks a lot . I changed little for Code First EF6.
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Entity.Core.EntityClient;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data
{
public class SingleConnection
{
private SingleConnection() { }
private static SingleConnection _ConsString = null;
private String _String = null;
public static string ConString
{
get
{
if (_ConsString == null)
{
_ConsString = new SingleConnection { _String = SingleConnection.Connect() };
return _ConsString._String;
}
else
return _ConsString._String;
}
}
public static string Connect()
{
string conString = ConfigurationManager.ConnectionStrings["YourConnectionStringsName"].ConnectionString;
if (conString.ToLower().StartsWith("metadata="))
{
System.Data.Entity.Core.EntityClient.EntityConnectionStringBuilder efBuilder = new System.Data.Entity.Core.EntityClient.EntityConnectionStringBuilder(conString);
conString = efBuilder.ProviderConnectionString;
}
SqlConnectionStringBuilder cns = new SqlConnectionStringBuilder(conString);
string dataSource = cns.DataSource;
SqlConnectionStringBuilder sqlString = new SqlConnectionStringBuilder()
{
DataSource = cns.DataSource, // Server name
InitialCatalog = cns.InitialCatalog, //Database
UserID = cns.UserID, //Username
Password = cns.Password, //Password,
MultipleActiveResultSets = true,
ApplicationName = "EntityFramework",
};
//Build an Entity Framework connection string
EntityConnectionStringBuilder entityString = new EntityConnectionStringBuilder()
{
Provider = "System.Data.SqlClient",
Metadata = "res://*",
ProviderConnectionString = sqlString.ToString()
};
return entityString.ConnectionString;
}
}
}
You can use singleton patter for it . For example
private YouurDBContext context;
public YouurDBContext Context
{
get
{
if (context==null)
{
context = new YouurDBContext();
}
return context;
}
set { context = value; }
}
This is my settings.cs class:
public class Settings
{
static FileIniDataParser _parser = new FileIniDataParser();
IniData _data = _parser.ReadFile("Config.ini");
public int GetInt(string section, string key)
{
string keyValue = _data[section][key];
int setting = int.Parse(keyValue);
return setting;
}
}
This will crash if Config.ini doesn't exist because it tries to read from a file that doesn't exist. But in order for me to make the file I first have to make an instance of the object. But when making the instance it crashes.
I can always do this to make it work, but if I do that I have to repeat my self when making GetBool
public int GetInt(string section, string key)
{
FileIniDataParser _parser = new FileIniDataParser();
IniData _data = _parser.ReadFile("Config.ini");
string keyValue = _data[section][key];
int setting = int.Parse(keyValue);
return setting;
}
And repeating your self is never good.
Just check if the file exists before reading it and put everything in the definition of the _data field in the default constructor of the Settings class:
public class Settings
{
static FileIniDataParser _parser = new FileIniDataParser();
IniData _data;
public Settings()
{
if (!File.Exists("Config.ini"))
{
// create the config file
}
_data = _parser.ReadFile("Config.ini");
}
public int GetInt(string section, string key)
{
string keyValue = _data[section][key];
int setting = int.Parse(keyValue);
return setting;
}
}
In addition to Steffens answer which provides the "how to solve" here is the "why to do so".
Generally you should never create instances that cannot be used. Creating an instance of Setting that excplicitely needs a file where the file does not exist should ALLWAYS throw an exeption. Using any methods on such an instances makes no sense at all as ALL of them will fail.
So check if the file exists (see Steffens answer on how to) within the ctor and if not throw an exception.
Use a FactoryMethod, initialising an object using IO in a (static) constructor is always a bad idea.
public class Settings
{
private readonly IniData _data;
private Settings(IniData data){
_data = data;
}
public static Settings InitFrom(string fname){
var _parser = new FileIniDataParser();
var data = _parser.ReadFile(fname);
return new Settings(data);
}
public int GetInt(string section, string key)
{
string keyValue = _data[section][key];
int setting = int.Parse(keyValue);
return setting;
}
}
Now you can create the Settings in a controlled way:
try{
var settings = Settings.InitFrom("Config.ini");
}
catch(IOException iox){
//something useful
}
var x = settings.GetInt("section","key");
And you make the clear that initialisation is more expensive then just a new {}
I'm having trouble using a third party API that has outdated documentation, so I'm trying to figure out why this piece of ##$! isn't working. And by ##$! i mean "code", of course :)
So as far as i know WAPISoap is a public interface that I have obtained by adding a web reference in visual studio.
I also know the Describe() method accepts two parameters, a string and an object of type credential and it returns a string. Any help would be greatly appreciated :)
Here's what i got so far:
using WAPIClient;
using System;
using Project1.WsWWDAPI;
namespace WAPIClient
{
class ResellerAPI
{
public void CallDescribe()
{
String sReturnXml;
Credential m_Crededential = new Project1.WsWWDAPI.Credential();
m_Crededential.Account = "account";
m_Crededential.Password = "password";
String sCLTRID = System.Guid.NewGuid().ToString();
sReturnXml = WAPISoap.Describe(sCLTRID, m_Crededential);
Console.WriteLine(sReturnXml);
}
static void Main(string[] args)
{
ResellerAPI reseller = new ResellerAPI();
reseller.CallDescribe();
}
}
}
The Describe method is not static, which means you need to call it on an instance of the WAPI class:
WsWWDAPI.WAPI m_WAPIObj = null;
WsWWDAPI.Credential m_Crededential = null;
public void Init()
{
m_WAPIObj = new WsWWDAPI.WAPI();
m_Crededential = new WsWWDAPI.Credential();
m_Crededential.Account = "account";
m_Crededential.Password = "password";
}
public void CallDescribe()
{
String sReturnXml;
String sCLTRID = System.Guid.NewGuid().ToString();
sReturnXml = m_WAPIObj.Describe(sCLTRID, m_Crededential);
Console.WriteLine( sReturnXml );
}
static void Main(string[] args)
{
ResellerAPI reseller = new ResellerAPI();
reseller.Init();
reseller.CallDescribe();
}
See: http://products.secureserver.net/guides/wsapiquickstart.pdf
The error is because you use non-static method in static context - you should have instance of the WAPISoap in order to call member function which is not static
It sounds like you need to create an instance of WAPISoap and then call Describe on that instance.
I have a system that supports multiple products. Each product has its own database with the same exact schema.
When I pass in the connection string as a parameter to my Data Context constructor it always uses the default database listed in the connection string, or the default database of the user connecting if I do not provide an Initial Catalog in the connection string.
I would like to be able to have the system utilize a database without having to change the connection string and by passing in the database name as a parameter.
Here is an example of the code I am using:
class Program
{
static void Main(string[] args)
{
var d = new Data("Data Source=(LOCAL);Initial Catalog=Database1;Integrated Security=true;");
var d1 = new Data("Data Source=(LOCAL);Initial Catalog=Database2;Integrated Security=true;");
Console.ReadLine();
}
}
internal class Data
{
public Data(string connection)
{
using (var ctx = new DataClassDataContext(connection))
{
var query = from c in ctx.MyTable select c;
try
{
Console.WriteLine(query.Count());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
If this code gets executed, then the first result will pull from Database1 and the second result will pull from Database2. I would like it to have the ability to pull from a database that is not provided in the connection string. The reason for this is because the database could change based on a specific scenario but the connection string will remain the same.
Here is an example of what I am using to "fake" it, but I don't really think this is the best solution for this:
class oConnection
{
public string Server { get; set; }
public string Database { get; set; }
public bool IntegratedSecurity { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
class Program
{
static void Main(string[] args)
{
var d = new Data(new oConnection
{
Database = "Database1",
Server = "(Local)",
IntegratedSecurity = true
});
var d1 = new Data(new oConnection
{
Database = "Database2",
Server = "(Local)",
IntegratedSecurity = true
});
Console.ReadLine();
}
}
internal class Data
{
private static string BuildConnection(oConnection connection)
{
var sb = new StringBuilder();
sb.Append("Data Source=" + connection.Server + ";Initial Catalog=" + connection.Database + ";");
if(connection.IntegratedSecurity)
{
sb.Append("Integrated Security=true;");
}
else
{
sb.Append("user id=" + connection.UserName + ";password=" + connection.Password);
}
return sb.ToString();
}
public Data(oConnection connection)
{
using (var ctx = new DataClassDataContext(BuildConnection(connection)))
{
var query = from c in ctx.MyTable select c;
try
{
Console.WriteLine(query.Count());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
Another note: the goal of this is really to be able to support not having multiple different connection strings when running queries that will span across multiple databases. For example: If I want to query the account records from a database and then query some sort of lookup data from another database, I would have to create a new connection string for the context.
Any help would be appreciated.
Thanks
Use the constructor that receives System.Data.IDbConnection connection. You can use the same connection string, and call connection.ChangeDatabase("mydb") before passing it to the constructor. Alternatively you can add a new constructor on the partial class, so the calling call doesn't has to deal with that.
you can use the SqlConnectionStringBuilder
class