How put connection in report runtime - c#

I would like send connection for report in DevExpress, and send query for this report I call report with code bellow:
private void Form14_Load(object sender, EventArgs e)
{
try {
XtraReport report = XtraReport.FromFile(#"C:\\a\\Report2.repx", true);
ReportPrintTool printTool = new ReportPrintTool(report);
printTool.ShowPreviewDialog();
}
catch (Exception ex) {
MessageBox.Show(ex.ToString());
}
}

In the general case, your report is connected to data via the SqlDataSource component. So, I suggest you update the connection at the SqlDataSource instance level. For that purpose, just get the existing data source from your XtraReport class:
var sqlDataSource = xtraReport.DataSource as SqlDataSource;
sqlDataSource.ConnectionParameters = ...;
Please refer to the Specify data connection article to learn how to change the data source's connection parameters.

You can create your own report implementation where you can update the connection string by checking the connection strings used in the reports and the sub reports.
In below example, a Typed Dataset is used to create the reports and then you can update the connection string of the table adapters on the initialization.
Refere this below implementation:
// Base Report
public partial class BaseReport: DevExpress.XtraReports.UI.XtraReport, IDisposable
{
public List<SQLiteConnection> GetConnectionList
{
get { return connectionList; }
}
public List<SimergyBaseReport> GetSubReportList
{
get { return subReportList; }
}
protected List<SQLiteConnection> connectionList = new List<SQLiteConnection>();
protected List<SimergyBaseReport> subReportList = new List<SimergyBaseReport>();
public void UpdateConnectionString(String connectionString)
{
#if !RPT_DESIGN
connectionString = GlobalUtilities.GetOutputConnectionString(connectionString);
foreach (SQLiteConnection conn in connectionList)
{
conn.Close();
conn.ConnectionString = connectionString;
reportDataSet.Clear();
}
foreach (BaseReport subReport in comparisonSubReportList)
{
if (subReport != null)
subReport.UpdateConnectionString(connectionString);
}
#endif
}
}
// Report
public partial class UsageSummary : Simergy.Reporting.Reports.BaseReport
{
public ClimaticSummary()
{
InitializeComponent();
}
public ClimaticSummary(String connectionString, Model model)
: base(model)
{
InitializeComponent();
connectionList.Add(applicationUsageTableAdapter.Connection);
connectionList.Add(dailyUsage_SUMMARYTableAdapter.Connection);
subReportList.Add(xrSubreport1.ReportSource as BaseReport);
subReportList.Add(xrSubreport2.ReportSource as BaseReport);
subReportList.Add(footerSubReport.ReportSource as BaseReport);
reportDataSet = report_DataSet1;
UpdateConnectionString(connectionString);
}
}
// Custom print control to render the reports
public partial class ReportViewControl : PrintControl
{
private SimergyBaseReport CurrentReport = null;
public ReportViewControl()
{
InitializeComponent();
}
public void SetReport(SimergyBaseReport report)
{
CurrentReport = report;
if (CurrentReport != null)
{
this.PrintingSystem = report.PrintingSystem;
SetupButtonVisability();
report.CreateDocument();
report.RecreateDocumentMap();
this.PrintingSystem = report.PrintingSystem;
}
}
public void RefreshReport()
{
this.PrintingSystem = null;
this.PrintingSystem = CurrentReport.PrintingSystem;
CurrentReport.CreateDocument(true);
}
}
///Usage
BaseReport report = new UsageSummary(someConnectionString);
ReportViewControl viewer = new ReportViewControl();
viewer.SetReport(report);
form1.Controls.Add(viewer);

Related

How can I connect to multiple db schemas? (C# / MySQL)

I've created a class that confirms if it's able to connect to a db on mysql using login info provided via string CadenaConexion. How can I process an additional db and have the code connect to both when executing?
First I create a connection and assign the login info (here is where I'd add the second db):
using MySql.Data.MySqlClient;
namespace DBManager
{
public class DBConexion
{
protected MySqlConnection oConexion;
String CadenaConexion = "Server=localhost; Port=3306;Database=blabla;Uid=root;Pwd=blabla; AllowZeroDateTime=True;";
string _estado;
public string Estado
{
get => _estado;
}
Then I determine if connected or not through a boolean variable:
public Boolean Conectar()
{
Boolean Conectado = false;
oConexion = new MySqlConnection(CadenaConexion);
try
{
oConexion.Open();
Conectado = true;
}
catch
{
Conectado = false;
}
_estado = oConexion.State.ToString();
return Conectado;
}
Optional method to confirm if successful, as it will not perform the disconnect unless it was previously connected:
public void Desconectar()
{
try
{
if (oConexion.State == System.Data.ConnectionState.Open)
{
try
{
oConexion.Close();
}
catch
{
}
}
_estado = oConexion.State.ToString();
}
catch
{
_estado = "Indefinido";
}
}

Unable to change label text when Invoking Method through Reflection in c#

First Look at my code
namespace HealthClub
{
public partial class frmTrainerMaster : Form
{
DataTable dt = new DataTable();
frmHome Home = new frmHome();
public frmTrainerMaster()
{
InitializeComponent();
}
}
private void frmTrainerMaster_Load(object sender, EventArgs e)
{
FillValues("UserNameText");
}
public void FillValues(string UserName)
{
DataTable DT;
SqlCommand cmd = new SqlCommand();
try
{
cmd.Connection = Connections.Connection[UserName];
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "TrainerMaster_pro";
cmd.Parameters.AddWithValue("Option", "FillValues".Trim());
if (Connections.Connection[UserName].State == ConnectionState.Closed)
Connections.Connection[UserName].Open();
SqlDataAdapter adp = new SqlDataAdapter(cmd);
DT = new DataTable();
adp.Fill(DT);
lblId___.Text = DT.Rows[0][0].ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
cmd.Parameters.Clear();
cmd.Dispose();
Connections.Connection[UserName].Close();
}
}
}
Now I am calling FillValues() from another class like this
class AnotherClass
{
public void TestMethod(string FormName)
{
Type tp = Type.GetType("HealthClub." + FormName);
object myobj = Activator.CreateInstance(tp);
MethodInfo method = myobj.GetType().GetMethod("FillValues");
object[] parametersArray = new object[] { UserName };
method.Invoke(myobj, parametersArray);
}
}
If you look at the FillValues(), I am assigning the database value to a label. When I am calling it in my first class in page load it's working fine.
But when I am Invoking the medthod from second class, Method invokes but database value does not assign to the label.
What extra effort I need to do ?
There is a class and there is an instance. This is very basic concept you need to understand (not just in C#, but in any objective-oriented language).
// class example
class FrmTrainerMaster { public int SomeProperty { get; set;} }
When you create new instance:
// creates one window
var frmTrainerMasterInstanceOne = new FrmTrainerMaster();
frmTrainerMasterInstanceOne.SomeProperty = 1;
// creates second window
var frmTrainerMasterInstanceTwo = new FrmTrainerMaster();
frmTrainerMasterInstanceTwo.SomeProperty = 2;
Instances are SEPARATE - so at this point querying
// will return 1
Console.Out.WriteLine(frmTrainerMasterInstanceOne.SomeProperty);
// will return 2
Console.Out.WriteLine(frmTrainerMasterInstanceTwo.SomeProperty);
With reflection var myobj = Type.GetType("HealthClub.FrmTrainerMaster"); is equal to var myobj = new FrmTrainerMaster(); so by doing anything with myobj, you still can't affect frmTrainerMasterInstanceOne or frmTrainerMasterInstanceTwo.
What do you need is actually method how to pass reference to instance (of FrmTrainerMaster class) to place where you need it (lets call it AnotherForm), there is no magic list of all instances for given class unless you explicitly build it.
public partial class FrmTrainerMaster : Form
{
public void FillValues(string userName) { ... }
}
One way is via constructor injection (generally proffered - since at time when object (AnotherForm) is constructed you have it in valid state (i.e. with all dependencies initialized).
public class AnotherForm : Form {
private readonly FrmTrainMaster _frmTrainMaster;
public AnotherForm(FrmTrainMaster frmTrainMaster) {
if (frmTrainMaster == null) {
throw new ArgumentNullException(nameof(frmTrainMaster));
}
_frmTrainMaster = frmTrainMaster;
}
}
Or via setter injection:
public class AnotherForm : Form {
private FrmTrainMaster _frmTrainMaster;
public FrmTrainMaster MasterForm { set { _frmTrainMaster = value; } }
}
Either way the reflection is not necessary at all. At any place in your AnotherForm you can just call
class AnotherForm : Form {
...
public void FooMethodThatCallFillValues() {
_frmTrainMaster.FillValues("...");
}
}

How to write a custom Orchard session locator by implementing Orchard.Data.ISessionLocator?

I need to migrate some data in an Orchard module running within a Orchard 1.9.0 installation. The issue here is that the data is stored in a foreign DB on another server, not in the Orchard DB. So when the migration class methods get called, internally Orchard uses the Orchard.Data.ISessionLocator interface to retrieve the DB connection. Sadly overriding this behavior is not possible but i had the idea to hook into the session locator thing by creating a custom session locator.
The custom session locator looks like this and is based on the existing class Orchard.Data.SessionLocator:
public class CustomSessionLocator : Orchard.Data.ISessionLocator, Orchard.Data.ITransactionManager, System.IDisposable
{
// public
public CustomSessionLocator(Orchard.Data.ISessionFactoryHolder aSessionFactoryHolder)
{
Logger = Orchard.Logging.NullLogger.Instance;
IsolationLevel = System.Data.IsolationLevel.ReadCommitted;
mSessionFactoryHolder = aSessionFactoryHolder;
mSessions = new System.Collections.Generic.Dictionary<SessionScope, NHibernate.ISession>();
if (mForeignDBConnection == null)
{
string lConnectionString = "data source=myServer;initial catalog=myDB;persist security info=True;user id=xxx;password=xxx;MultipleActiveResultSets=True;";
mForeignDBConnection = new System.Data.SqlClient.SqlConnection(lConnectionString);
}
}
public NHibernate.ISession For(System.Type aEntityType)
{
Logger.Debug("Acquiring session for {0}", aEntityType);
Demand();
return mSessions[CurrentSessionScope];
}
public void Demand()
{
EnsureSession(IsolationLevel);
}
public void RequireNew()
{
RequireNew(IsolationLevel);
}
public void RequireNew(System.Data.IsolationLevel aLevel)
{
DisposeSession();
EnsureSession(aLevel);
}
public void Cancel()
{
NHibernate.ISession lSession;
if (mSessions.TryGetValue(CurrentSessionScope, out lSession) && lSession != null && !lSession.Transaction.WasRolledBack && lSession.Transaction.IsActive)
{
Logger.Debug("Rolling back transaction");
lSession.Transaction.Rollback();
}
}
public void Dispose()
{
DisposeSession();
}
public enum SessionScope
{
OrchardDefault,
ForeignDB
}
public Orchard.Logging.ILogger Logger { get; set; }
public System.Data.IsolationLevel IsolationLevel { get; set; }
public SessionScope CurrentSessionScope { private get; set; }
// private
private void DisposeSession()
{
NHibernate.ISession lSession;
if (mSessions.TryGetValue(CurrentSessionScope, out lSession) && lSession != null)
{
try
{
if (!lSession.Transaction.WasRolledBack && lSession.Transaction.IsActive)
{
Logger.Debug("Committing transaction");
lSession.Transaction.Commit();
}
}
finally
{
Logger.Debug("Disposing session");
var lConnection = lSession.Connection;
lSession.Close();
lSession.Dispose();
lSession = null;
mSessions[CurrentSessionScope] = null;
}
}
}
private void EnsureSession(System.Data.IsolationLevel aLevel)
{
NHibernate.ISession lSession;
if (mSessions.TryGetValue(CurrentSessionScope, out lSession) && lSession != null)
return;
var lSessionFactory = mSessionFactoryHolder.GetSessionFactory();
Logger.Debug("Opening NHibernate session");
if (CurrentSessionScope == SessionScope.ForeignDB)
{
lSession = lSessionFactory.OpenSession(mForeignDBConnection);
// open connection otherwise the following lSession.BeginTransaction() fails with exception
if (mForeignDBConnection.State == System.Data.ConnectionState.Closed)
mForeignDBConnection.Open();
}
else
lSession = lSessionFactory.OpenSession();
mSessions[CurrentSessionScope] = lSession;
lSession.BeginTransaction(aLevel);
}
private readonly Orchard.Data.ISessionFactoryHolder mSessionFactoryHolder;
private System.Collections.Generic.Dictionary<SessionScope, NHibernate.ISession> mSessions;
private static System.Data.SqlClient.SqlConnection mForeignDBConnection;
}
Then i have a migration data interpreter that looks like this:
public class ForeignDataMigrationInterpreter : Orchard.Data.Migration.Interpreters.DefaultDataMigrationInterpreter
{
public ForeignDataMigrationInterpreter(
Orchard.Environment.Configuration.ShellSettings aShellSettings,
Orchard.Data.ISessionLocator aSessionLocator,
System.Collections.Generic.IEnumerable<Orchard.Data.Migration.Interpreters.ICommandInterpreter> aCommandInterpreters,
Orchard.Data.ISessionFactoryHolder aSessionFactoryHolder,
Orchard.Reports.Services.IReportsCoordinator aReportsCoordinator)
: base(aShellSettings, aSessionLocator, aCommandInterpreters, aSessionFactoryHolder, aReportsCoordinator)
{
mSessionLocator = aSessionLocator as CustomSessionLocator;
}
public override void Visit(Orchard.Data.Migration.Schema.CreateTableCommand aCommand)
{
#if LIVE
if (IsForeignDBCommand(aCommand.Name, ""))
mSessionLocator.CurrentSessionScope = CustomSessionLocator.SessionScope.ForeignDB;
else
mSessionLocator.CurrentSessionScope = CustomSessionLocator.SessionScope.OrchardDefault;
#endif
base.Visit(aCommand);
}
...
private bool IsForeignDBCommand(...)
{
return ...;
}
private CustomSessionLocator mSessionLocator;
}
As you can see, the basic procedure with foreign data is
Start Orchard
Migration class method is called which contains SchemaBuilder.CreateTable()
ForeignDataMigrationInterpreter.Visit(CreateTableCommand) is called
CurrentSessionScope of custom session locator is updated to SessionScope.ForeignDB
CreateTableCommand is passed into base class
CustomSessionLocator.For() is called which
ends in CustomSessionLocator.EnsureSession() which
returns the session X for scope SessionScope.ForeignDB
base class enlists CreateTableCommand to transaction of session X
fast forward some unrelated additional steps and the transaction is commited BUT it never returns and a timeout exception occures
My questions are
Is it even possible to migrate foreign data this way?
Why does timeout occur?

Entity Framework Tracing provider wrapper without config files

I would like to use Entity Framework Code first approach with SQLCE4 database. Everything seems to be really nice but I have problem with debugging sql queries. I found that EFTracing from http://efwrappers.codeplex.com/ should be exactly what I need but I don't know how to use it without app.config file. I am not big fan of this configuration. I want to use only C# code to set everything up and running. I think it should be fine to use code like this:
using (System.Data.Common.DbConnection c =
new EFTracingProvider.EFTracingConnection(
new System.Data.SqlServerCe.SqlCeConnection(conn)))
{
using (var context = new MyContext(c))
{
var a = from data in context.Projects select data;
}
}
But it doesn't work. It throws exception:
Unable to determine the provider name for connection of type
EFTracingProvider.EFTracingConnection'.
Is there any simple way how to correctly create wrapped connection only in code?
Solution for my problem is following DbContext object.
public class MyContext : DbContext
{
public MyContext()
: base(CreateConnection("Data Source=file.sdf",
"System.Data.SqlServerCe.4.0"), true)
{ }
public DbSet<Project> Projects { get; set; }
public static bool TraceEnabled = true;
private static DbConnection CreateConnection(string connectionString,
string providerInvariantName)
{
DbConnection connection = null;
if (TraceEnabled)
{
EFTracingProviderConfiguration.RegisterProvider();
EFTracingProviderConfiguration.LogToConsole = true;
string wrapperConnectionString = String.Format(#"wrappedProvider={0};{1}",
providerInvariantName, connectionString);
connection = new EFTracingConnection()
{
ConnectionString = wrapperConnectionString
};
}
else
{
DbProviderFactory factory = DbProviderFactories.GetFactory(providerInvariantName);
connection = factory.CreateConnection();
connection.ConnectionString = connectionString;
}
return connection;
}
}
So now I can use just context and connection is created automatically for wrapped or unwrapped SqlCe depending on TraceEnabled property.
using (var context = new MyContext())
{
var a = context.Projects.FirstOrDefault();
}
The genuine way to trace SQL queries is to call the ToString method like that :
var t = from c in _entities.CompanyDetail
select c;
string test = t.ToString();
I don't know EFTracing, but you might want to try MVCMiniProfiler. Despite the name MVCMiniProfiler also provide SQL queries profiling and work without config file.
I've done this by creating a wrapper class around the ObjectContext and using that wrapper instead of the original context. Here's an example context wrapper:
public partial class LoggedContext : MyContext
{
public LoggedContext()
: this("name=MyEntities") // Adjust this to match your entities
{
}
public LoggedContext(string connectionString)
: base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(connectionString)
{
}
private EFTracingConnection TracingConnection
{
get { return this.UnwrapConnection<EFTracingConnection>(); }
}
public event EventHandler<CommandExecutionEventArgs> CommandExecuting
{
add { this.TracingConnection.CommandExecuting += value; }
remove { this.TracingConnection.CommandExecuting -= value; }
}
public event EventHandler<CommandExecutionEventArgs> CommandFinished
{
add { this.TracingConnection.CommandFinished += value; }
remove { this.TracingConnection.CommandFinished -= value; }
}
public event EventHandler<CommandExecutionEventArgs> CommandFailed
{
add { this.TracingConnection.CommandFailed += value; }
remove { this.TracingConnection.CommandFailed -= value; }
}
}
I also have a static class that defines the tracing output method and has a static method to initialize tracing. Here:
public static class EFTracingExtensions
{
private static ILogger _logger;
public static void InitSqlTracing(ILogger logger)
{
_logger = logger;
EFTracingProviderConfiguration.RegisterProvider();
if (logger.IsLoggingEnabled()) // Don't add logging hooks if logging isn't enabled
{
EFTracingProviderConfiguration.LogAction = new Action<CommandExecutionEventArgs>(AppendSqlLog);
}
}
private static void AppendSqlLog(CommandExecutionEventArgs e)
{
if (e.Status != CommandExecutionStatus.Executing) // we only care about Finished and Failed
{
StringBuilder msg = new StringBuilder(e.ToTraceString().TrimEnd());
msg.Append(Environment.NewLine);
if (e.Result is SqlDataReader)
{
int rows = ((SqlDataReader)e.Result).HasRows ? ((SqlDataReader)e.Result).RecordsAffected : 0;
msg.AppendFormat("*** {0} rows affected", rows);
}
else if (e.Result is int)
{
msg.AppendFormat("*** result: {0}", e.Result);
}
else
{
msg.AppendFormat("*** finished, result: {0}", e.Result);
}
msg.Append(Environment.NewLine);
msg.AppendFormat(" [{0}] [{1}] in {2} seconds", e.Method, e.Status, e.Duration);
_logger.Log(msg.ToString(), LoggerCategories.SQL);
}
}
}
ILogger is the logging interface I'm using. You need to substitute your own interface/methods.
The InitSqlTracing method is invoked once when my program starts up, and then the LoggedContext class is used to log all the SQL generated by Entity Framework.
Putting it all together with your sample code:
EFTracingExtensions.InitSqlTracing(logger); // only call this once
using (var context = new LoggedContext())
{
var a = from data in context.Projects select data;
}

C# unitesting method with MySql query

I've made an attempt to unit test a methods in the database layer of my app. In my test I was planning to write mocks to avoid having a live connection to MySQL.
I'll write down a simplified version of my code to illustrate. Let's start with the unit test:
[TestMethod()]
public void TestMethod1()
{
DataBaseInterface database = new DataBaseInterface(); // this is the class which has the method I want to unit test
DataSet ds = new DataSet();
ds.Tables.Add(new DataTable("signals"));
ds.Tables[0].Columns.Add(new DataColumn("ID"));
ds.Tables[0].Columns.Add(new DataColumn("Content"));
DataRow row = ds.Tables[0].NewRow();
row["ID"] = "1";
row["Content"] = "Foo";
ds.Tables[0].Rows.Add(row);
MockDataBaseConnection db = new MockDataBaseConnection();
string result = database.GetContent(1); // this is the method I want to unit test
}
The method I want to unit test looks something like this:
public class DatabaseInterface
{
private MySqlConnectionAdapter _sqlConn;
public string GetContent(int i)
{
MySqlCommand command = _sqlConn.CreateCommand();
command.CommandText = String.Format("");
_sqlConn.Open();
MySqlDataReader reader = command.ExecuteReader();
/// more code here
}
To prevent using an actual database connection in my unitest I wrote a few mockups and here lies the problem.
The mockups looks like this:
public class MySqlConnectionAdapter
{
public MySqlConnection _sqlConn;
public MySqlConnectionAdapter()
{
}
public MySqlConnectionAdapter(string con)
{
_sqlConn = new MySqlConnection(con);
}
public event MySqlInfoMessageEventHandler InfoMessage
{
add
{
_sqlConn.InfoMessage += value;
}
remove
{
_sqlConn.InfoMessage -= value;
}
}
public virtual event StateChangeEventHandler StateChange
{
add
{
_sqlConn.StateChange += value;
}
remove
{
_sqlConn.StateChange -= value;
}
}
public virtual void Open()
{
_sqlConn.Open();
}
public void Close()
{
_sqlConn.Close();
}
public string ServerVersion
{
get
{
return _sqlConn.ServerVersion;
}
}
protected DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
{
return _sqlConn.BeginTransaction(isolationLevel);
}
public void ChangeDatabase(string databaseName)
{
_sqlConn.ChangeDatabase(databaseName);
}
public string ConnectionString
{
get
{
return _sqlConn.ConnectionString;
}
set
{
_sqlConn.ConnectionString = value;
}
}
public virtual MySqlCommand CreateCommand()
{
return _sqlConn.CreateCommand();
}
public string DataSource
{
get
{
return _sqlConn.DataSource;
}
}
public string Database
{
get
{
return _sqlConn.Database;
}
}
public ConnectionState State
{
get
{
return _sqlConn.State;
}
}
}
public class MockDataBaseConnection : MySqlConnectionAdapter
{
public DataSet ds;
public new MockMySqlCommand CreateCommand()
{
return new MockMySqlCommand(ds);
}
}
public class MockMySqlCommand
{
private DataSet _ds;
public MockMySqlReader ExcecuteReader()
{
return new MockMySqlReader(_ds);
}
public MockMySqlCommand(DataSet ds)
{
_ds = ds;
}
}
public class MockMySqlReader
{
public DataSet _ds;
private int currRow = 0;
public MockMySqlReader(DataSet ds)
{
_ds = ds;
}
public bool Read()
{
if (currRow < _ds.Tables[0].Rows.Count)
{
currRow++;
return true;
}
else return false;
}
public object GetValue(int i)
{
return _ds.Tables[0].Rows[currRow][i];
}
}
When the line _sqlConn.CreateCommand() is executed it throws and exeption. Why is that?
The _sqlConn fiels in my unit test method is a MockDataBaseConnection object and I want it to return a MockMySqlCommand object.
The sealed classed of the MySQL dll is giving me a headache. Can anyone explain how I can fix my code or show a simple example of how to unit test a method
which queries a database without actually querying the database.
Like suggested by vulkanino, I think it would be a lot easier to setup a local database instance, and run the tests directly on it.
I've been in the same situation, and developed this project that simply sets up a local running MySql test server instance, without you having to care about server administration: https://github.com/stumpdk/MySql.Server

Categories

Resources