Using MySQL with visual studio and changing the connection at runtime - mysql

I use something like this for my application
MySqlConnection cnn = new MySqlConnection("Server=myServerAddress;" +
"Database=myDataBase;" +
"Uid=myUsername;" +
"Pwd=myPassword;");
And this changes everytime because we deploy databases with our application.
It works fine. I type in using(new connection(cnn)){ query... } and go.
And I've got it working with a dataset using a connection defined in the windows ODBC datasouce administrator.
But I'm curious, is there a way to use visual studio's dataset items using the my local test db and then change the connection of the dataset at runtime? Even better, can I use c# to programmatically add the ODBC data source at runtime?

Usually a connection string is loaded from the application exe.config file present in the same folder of the application. This connection string could be defined using the Settings tab in the project properties.
Right click on Properties of your project
Select the Settings tab (confirm the creation if you have no
settings)
Click on the ComboBox in the column type and select Connection String
Give a symbolic name to your connection
Type the connection string in the Value column (Examples at
connectionstrings.com)
Now in your project files you should have the file app.config (that becomes yourapp.exe.config) where there is a section like this
<configuration>
<connectionStrings>
<add name="MyAppConnection"
connectionString="Server=myServerAddress;Database=myDB;Uid=user;Pwd=pass;" />
</connectionStrings>
</configuration
At this point you read it in the program using
string conString = ConfigurationManager
.ConnectionStrings["MyAppConnection"]
.ConnectionString;
Instead in a dynamic situation where you want to build yourself the connection string during runtime (from user inputs, your own configuration files and so on) then you could leverage the functionality of the class MySqlConnectionStringBuilder
MySqlConnectionStringBuilder msb = new MySqlConnectionStringBuilder();
msb.Server = "localhost";
msb.Port = 3306;
msb.UserID = "root";
msb.Password = "xxx";
msb.Database = "test";
MySqlConnection cnn = new MySqlConnection(msb.ConnectionString);
cnn.Open();
Of course, these literal values could be substituted by your own variables.
The documentation of this class is surprising difficult to find. The best docs are the one of the Sql Server equivalent. It is interesting that you could read a static connection string from your config file and then change only the property needed.
string conString = ConfigurationManager
.ConnectionStrings["MyAppConnection"]
.ConnectionString;
MySqlConnectionStringBuilder msb = new MySqlConnectionStringBuilder(conString);
msb.Database = "AnotherDB";
MySqlConnection cnn = new MySqlConnection(msb.ConnectionString);

Application connection string cannot be changed at runtime.
User settings can be changed.
Assuming you are using an application setting-property named "MyConnectionString" which holds the connection string for the entire application.
On your main Program class create a global string:
internal static string Prconnstring;
Create and save this settings.cs file:
namespace MYSOLUTIONORPROJECTNAME.Properties
{
// (Not sure where I found this solution some time ago)
// This class allows you to handle specific events on the settings class:
// The SettingChanging event is raised before a setting's value is changed.
// The PropertyChanged event is raised after a setting's value is changed.
// The SettingsLoaded event is raised after the setting values are loaded.
// The SettingsSaving event is raised before the setting values are saved.
internal sealed partial class Settings
{
public Settings()
{
// // To add event handlers for saving and changing settings, uncomment the lines below:
//
// this.SettingChanging += this.SettingChangingEventHandler;
//
// this.SettingsSaving += this.SettingsSavingEventHandler;
//
}
private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e)
{
// Add code to handle the SettingChangingEvent event here.
}
private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e)
{
// Add code to handle the SettingsSaving event here.
}
public override object this[string propertyName]
{
get
{
if (propertyName == "MyConnectionString")
{
return Program.Prconnstring;
}
else
{
return base[propertyName];
}
}
set
{
base[propertyName] = value;
}
}
}
}
Before calling-opening any object that uses the connection string (examples include Forms that use datasets or other classes that use datasets created on the development enviroment) create your new connection string by any means you think. (Example: You might want to use as user name in the connection string the current user. Create the connection string using the info provided form the environment.)
Program.Prconnstring = thenewruntimeconnectionstring.
Now whenever the application tries to get MyConnectionString (which is hardcoded in the myapplicationname.config and cannot be changed) instead gets the new thenewruntimeconnectionstring you provided to Program.Prconnstring.
Be aware that the development connection string will be available-visible to final user, since it is just a text file. If you do not want this, you can change that file (will be a file named NAMEOFMYAPPLICATION.exe.config) during deployment, since the connection string hardcoded there, will be of no use for the running app. Do not delete it, just change.

Your connection string will be stored in your App.config (or c# equivalent). Say it's called MyConnectionString. Just add My.Settings("MyConnectionString")="[your new connection string]" to your entry point to change to database binding at runtime. E.g:
Public Sub New()
' This call is required by the designer.
InitializeComponent()
My.Settings("MyConnectionString") = "server=remotedb.uk;user id=MainUser;password=2jdi38edhnche73g;database=mainDb;persistsecurityinfo=True;allowuservariables=True;defaultcommandtimeout=480;characterset=utf8mb4"
End Sub

Related

SSIS script task can't read project variable

In my project.params I have variables such as LampUserName of type string. In my
script task I'm then trying to read them like so:
foreach (var name in new string[] { "ServerName", "InitialCatalog", "UserName", "Password" }) {
if (!Dts.Variables.Contains(string.Format("$Project::Lamp{0}", name))) {
writer.WriteLine(name);
}
}
string server_name = (string)Dts.Variables["$Project::LampServerName"].Value;
string database = (string)Dts.Variables["$Project::LampInitialCatalog"].Value;
string username = (string)Dts.Variables["$Project::LampUserName"].Value;
string password = (string)Dts.Variables["$Project::LampPassword"].Value;
Every one of those prints out that it doesn't exist and then an exception is thrown. What am I doing wrong?
Are you referencing your project parameters from a Script Component within a Data Flow Task? If so, this differs from using a Script Task within the Control Flow. After adding the project parameter in the ReadOnlyVaraiables field, it is accessible as a property of the Variable object.
string database = Variables.DatabaseParameter.ToString();

Changing database type at runtime using EntityFramework

Is it possible to change database type at runtime? If yes, how it can be done? I am using EntityFramework 6.
Background about the question:
I have an application that initially does not have database access. A user first has to go through "installation" process and provide information about the database(including database type eg. MySql or MsSql).
I would like to avoid having 2 contexts if possible. If necessary I can provide more details.
You can specify the connection string at runtime using the following...
DbContext has a constructor that can be overloaded with the name of the connection string, or the connection string itself.
public partial class EntityName: DbContext {
public EntityName(): base("name=EntityName") {}
public EntityName(string connectionString): base(connectionString) {}
}
var connString = "PopulateConnString";
Using (var ctx = new EntityName(EntityConnectionStringBuilder)
{
// Do stuff
}

How can I get a report URL via the SSRS Web Service?

In my project I have a web reference to SSRS (2005). I would like to display links that can take users directly to rendered reports. I know I can provide a link such as this one:
http://server/ReportServer/Pages/ReportViewer.aspx?/path/to/report&rs:Command=Render&rc:parameters=false&rs:format=HTML4.0
The question is how can I get that URL from the web service? And if the report takes parameters is there a way to provide values to the web service and have it format the URL for me?
I know I can build the URL myself, but I don't like reinventing wheels.
There are a few things to think of about HOW SSRS works and HOW MUCH TIME you want to invest in monkeying with it.
I. You can traverse the root but I highly doubt you meant that. From the root you can add items whether they are directories or reports. And to add to that you can add the parameter directly to the Rest URI to render a report and you may also output a value as well. For example:
Main part of address root:
http:// <server>/ReportServer/Pages/ReportViewer.aspx?
path to directory:
%2fTest
path to report (labeled it the same name lol)
%2fTest
what to do with it? (render it)
&rs:Command=Render
Put a paremeter in and execute it as well (Yes I called my parameter Test too!)
&Test=Value
Put it all together:
http:// <servername>/ReportServer/Pages/ReportViewer.aspx?%2fTest%2fTest&rs:Command=Render&Test=Value
II. You have a database you can query for traversing things but I believe MS does NOT document it well. Generally it is a SQL Server database named 'ReportServer' on whatever server you installed SSRS on. Generally most items are in the table 'dbo.Catalog' with 'Type' of 2 for reports. You can get their info and even parameters from them there.
III. You want to go full bore and dive into .NET and just talk to the service directly? You can do that too. You need the two main services though to do that:
A: http://<Server Name>/reportserver/reportservice2010 (gets info on existing items on server)
B: http:// <Server Name>reportserver/reportexecution2005 (gets info for in code creating reports to types directly in code)
I had another thread on exporting this here: Programmatically Export SSRS report from sharepoint using ReportService2010.asmx; but you will to get info as well probably. ONCE you have created the proxy classes (or made a reference to the web services) you can do code in .NET like so. These services do all the magic so without them you can't really model much in SSRS. Basically I create a class that you pass the 'SERVER' you need to reference to the class like 'http:// /ReportServer'.
private ReportingService2010 _ReportingService = new ReportingService2010();
private ReportExecutionService _ReportingExecution = new ReportExecutionService();
private string _server { get; set; }
public ReaderWriter(string server)
{
_server = server;
_ReportingService.Url = _server + #"/ReportService2010.asmx";
_ReportingService.Credentials = System.Net.CredentialCache.DefaultCredentials;
_ReportingExecution.Url = _server + #"/ReportExecution2005.asmx";
_ReportingExecution.Credentials = System.Net.CredentialCache.DefaultCredentials;
}
public List<ItemParameter> GetReportParameters(string report)
{
try
{
return _ReportingService.GetItemParameters(report, null, false, null, null).ToList();
}
catch (Exception ex)
{
MessageBox.Show("Getting Parameter info threw an error:\n " + ex.Message);
return new List<ItemParameter> { new ItemParameter { Name = "Parameter Not Found" } };
}
}
public List<CatalogItem> GetChildInfo(string dest)
{
try
{
return _ReportingService.ListChildren("/" + dest, false).ToList();
}
catch (Exception ex)
{
MessageBox.Show("Getting Child info of location threw an error:\n\n" + ex.Message);
return new List<CatalogItem> { new CatalogItem { Name = "Path Does Not exist", Path = "Path Does not exist" } };
}
}
ListChildren is the way to go. You can always set the second parameter to true to return all catalog items when you have reports in many folders.
Dim items As CatalogItem() = rs.ListChildren(reportPath, True)

Adobe AIR SQLResult listener reached, but no data in SQLite

I'm currently working on a project using AIR and Flex that uses a remote data source to persist data locally in a SQLite database. Currently, there's a lot of copy and paste code that I was trying to alleviate, so since we already use a DAO pattern with several common queries that get passed to it and a type that creates SQLStatement values, I figured I would simplify our codebase even more.
I applied the Adapter pattern to allow a wider range of possible database operations to be performed ([saveOrUpdate, find, findAll, remove] => [selectSingle, selectMultiple, insert, updateSingle, updateMultiple, deleteSingle, deleteMultiple]). I also applied the Strategy pattern to two aspects of the statement runner: the first time for what sort of aggregated type to return (either an Array of records or an ArrayCollection of records) for the selectMultiple function; the second time for creating or not creating historical records (ChangeObjects).
After applying these patterns and testing some refactored code, it worked perfectly with an existing SQLite database. I neglected to test its compatibility with the remote data source, since the saving mechanisms are used during that process as well. After refactoring and simplifying our code and nearing the end of the development cycle, I tested the download.
It would read data from the SQLite database, despite the fact that there was actually no data in it according to sqlite3.
I will give the related piece of code for this.
public class BaseDaoAdaptee {
private var returnStrategy: ReturnTypeStrategy;
private var trackingStrategy: TrackingStrategy;
private var creator: StatementCreator;
public function insert(queryTitle: String,
object: DaoAwareDTO,
parameters: Array,
mutator: Function,
handler: Function): void {
var statement: SQLStatement;
mutator = creator.validEmptyFunction(mutator);
handler = creator.validFault(handler);
statement = defaultStatement(queryTitle, parameters, handler);
statement.addEventListener(SQLEvent.RESULT,
trackingStrategy.onInserted(object, mutator), false, 0, true);
statement.execute();
}
}
The code for the TrackingStrategy implemented:
public class TrackedStrategy
implements TrackingStrategy {
public function onInserted(object: DaoAwareDTO,
callback: Function): Function {
return function (event: SQLEvent): void {
var change: Change,
id:Number = event.target.getResult().lastInsertRowID;
creator.logger.debug((event.target as SQLStatement).itemClass + ' (id # ' + id + ') inserted');
(object as Storeable).id = id;
change = new Creation(object);
change.register();
callback();
};
}
}
The logger reads that various database records were inserted, and when stopped on a breakpoint in the above lambda, "object" has all proper values. When running a Select statement in sqlite3, no records ever get returned.
Why would this happen?
Turns out an open transaction on a SQLConnection value was the cause. Got to love team projects. Commit or rollback your SQLConnection transactions!

SSIS Script Component connection

I've been searching for a solution for days now and I still cant seem to find one. I have a problem acquiring a connection in my Script component. I need to query my database to retrieve an Id to be used before I insert it in the
public override void AcquireConnections(object Transaction)
{
connMgr = base.Connections.Connection;
conn = (SqlConnection)connMgr.AcquireConnection(null);
}
I get an exception here.
System.InvalidCastException: Unable to cast COM object of type 'System.__ComObject' to class type 'System.Data.SqlClient.SqlConnection'. Instances of types that represent COM components cannot be cast to types that do not represent COM components; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface.
Any solutions?
For those that want to be able to do this in a Script Component:
Double Click the Script component to open the "Script Transformation Editor"
Click the "Connection Managers" list item.
Add a new Connection Manager. Select an existing ADO.NET connection manager.
Click on the "Script" list item and then the "Edit Script..." button.
You can do something like this inside your script:
using (SqlConnection connection = this.Connections.Connection.AcquireConnection(null) as SqlConnection)
{
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT [Value] FROM dbo.MyTable";
command.CommandType = CommandType.Text;
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
ProfanityWords.Add(reader.GetValue(0).ToString());
}
}
}
this.Connections.Connection.ReleaseConnection(connection);
}
ADO.NET connection manger should be created and refer into the code to type cast to the SqlConnection. If you dont have the ADO.NET connection in your SSIS pakcage you will get the TypeCast exception. Following steps should be used if you want to use the SqlConnection.
Create the ADO.NET connection.
Use the following line in your code.
var connObj = Dts.Connections["ADO.NETConnectionName"].AcquireConnection(null);
var sqlConn = (SqlConnection)connObj;
Once you done with your SQL connection. Use the following code to Close/ Release your connection.
Dts.Connections["ADO.NETConnectionName"].ReleaseConnection(connObj);
Hope this helps.