Change Crystal Reports DataSource From MSACCESS to SQLSERVER at runtime - crystal-reports

I have a winforms application that is connecting to an MSACCESS Database located on a network. I am very keen to change the underlying database to sqlserver database on our local server. I am able to convert the database and get the application running (all table names, fields etc are preserved).
The application has over 300 crystal reports, which are configured to connect to the access datasource. I really dont want to have to manually reconfigure every report... so I am looking for a way to change the datasource at runtime

thanks for the assist, this solution seems to work for me though:
private void getConnectionInfo(string serverName, string databaseName, string userID, string password)
{
connectionInfo.ServerName = serverName;
connectionInfo.DatabaseName = databaseName;
connectionInfo.UserID = userID;
connectionInfo.Password = password;
}
private TableLogOnInfo GetSQLTableLogOnInfo(string serverName, string databaseName, string userID, string password)
{
CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag connectionAttributes = new CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag();
connectionAttributes.EnsureCapacity(11);
connectionAttributes.Add("Connect Timeout", "15");
connectionAttributes.Add("Data Source", serverName);
connectionAttributes.Add("General Timeout", "0");
connectionAttributes.Add("Initial Catalog", databaseName);
connectionAttributes.Add("Integrated Security", false);
connectionAttributes.Add("Locale Identifier", "1033");
connectionAttributes.Add("OLE DB Services", "-5");
connectionAttributes.Add("Provider", "SQLOLEDB");
connectionAttributes.Add("Tag with column collation when possible", "0");
connectionAttributes.Add("Use DSN Default Properties", false);
connectionAttributes.Add("Use Encryption for Data", "0");
DbConnectionAttributes attributes = new DbConnectionAttributes();
attributes.Collection.Add(new NameValuePair2("Database DLL", "crdb_ado.dll"));
attributes.Collection.Add(new NameValuePair2("QE_DatabaseName", databaseName));
attributes.Collection.Add(new NameValuePair2("QE_DatabaseType", "OLE DB (ADO)"));
attributes.Collection.Add(new NameValuePair2("QE_LogonProperties", connectionAttributes));
attributes.Collection.Add(new NameValuePair2("QE_ServerDescription", serverName));
attributes.Collection.Add(new NameValuePair2("SSO Enabled", false));
getConnectionInfo(serverName, databaseName, userID, password);
connectionInfo.Attributes = attributes;
connectionInfo.Type = ConnectionInfoType.SQL;
TableLogOnInfo tableLogOnInfo = new TableLogOnInfo();
tableLogOnInfo.ConnectionInfo = connectionInfo;
return tableLogOnInfo;
}
public ReportDocument GenerateReport(string reportPath, string report, string folder, List<ReportParameters> parameters)
{
ReportDocument crReport = new ReportDocument();
TableLogOnInfo crTableLogoninfo = new TableLogOnInfo();
Tables crTables;
string path = reportPath + folder;
crReport.Load(path + report);
crTables = crReport.Database.Tables;
TableLogOnInfo tableLogonInfo = this.GetSQLTableLogOnInfo(this.serverName, this.databaseName, this.userName, this.password );
foreach (Table table in crTables)
{
table.LogOnInfo.ConnectionInfo = connectionInfo;
table.ApplyLogOnInfo(table.LogOnInfo);
}
foreach (ReportDocument subrep in crReport.Subreports)
{
foreach (Table table in subrep.Database.Tables)
{
table.LogOnInfo.ConnectionInfo = connectionInfo;
table.ApplyLogOnInfo(table.LogOnInfo);
}
}
crReport.Refresh();
foreach (ReportParameters r in parameters)
crReport.SetParameterValue(r.parameter, r.value);
return crReport;
}

Related

i want to enter data in a complete column without according to row data

i'm using sq lite database in android
i already have data in two columns i want to change data in column 2 without condition of where
where ever i searched where condition is used
this is how i stored
public boolean updateData(String name, String pass){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(col2,pass);
db.update(TABLE_NAME,contentValues, col1+" =?", new String[]{name});
return true;
}
Pass null for the 3d and 4th arguments:
public boolean updateData(String pass) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(col2, pass);
db.update(TABLE_NAME, contentValues, null, null);
db.close();
return true;
}
I guess you don't need the parameter name since there is no WHERE clause, so I removed it.

Unable to know how to link data between two tables

I'm learning RESTful webservices from javabrains website. Here there is a section named Comments and this is related to a message, But I'm unable to know How Can I link these both.
Below is my SQL Tables for Messages and comments.
Messages
Comments
Here Basically, both look pretty same(The table design), but the values differ. And I'm using the below method to send the data.
public Comment addComment(long messageId, Comment comment) throws Exception {
Properties properties = new Properties();
properties.load(getClass().getClassLoader().getResourceAsStream("/config.properties"));
String userName = properties.getProperty("user");
String password = properties.getProperty("pass");
String url = properties.getProperty("Sqldburl");
int key = 0;
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver").newInstance();
Connection conn = DriverManager.getConnection(url, userName, password);
String query = "select count(*) from Comments";
PreparedStatement ps = conn.prepareStatement(query);
ResultSet rs = ps.executeQuery();
rs.next();
key = rs.getInt(1);
} catch (Exception e) {
System.out.println(e);
}
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver").newInstance();
Connection conn = DriverManager.getConnection(url, userName, password);
String query = "insert into Comments(id, message, author) values(?,?,?)";
PreparedStatement ps = conn.prepareStatement(query);
ps.setInt(1, key);
ps.setString(2, comment.getMessage());
ps.setString(3, comment.getAuthor());
ps.executeQuery();
} catch (Exception e) {
System.out.println(e);
}
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver").newInstance();
Connection conn = DriverManager.getConnection(url, userName, password);
String query = "select * from Comments where messageId=?";
PreparedStatement ps = conn.prepareStatement(query);
ps.setLong(1, messageId);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
comment.setAuthor(rs.getString("Author"));
comment.setId(rs.getInt("Id"));
comment.setMessage(rs.getString("message"));
}
} catch (Exception e) {
System.out.println(e + "b3");
}
return comment;
}
After writing this code, I've realized that Here I'm adding a comment for sure into Comments table, But it is no where linked to the Messages.
I know a way, that is I've create a new column in the Comments table and using join operation, I need to update the same messageId in comments table. But I want to know if there is a better way of getting this done, without using the concept of joins.
In MessageBean, there is a map declared as below.
private Map<Long, Comment> comments = new HashMap<>();
#XmlTransient
public Map<Long, Comment> getComments() {
return comments;
}
public void setComments(Map<Long, Comment> comments) {
this.comments = comments;
}
can I take any advantage of this to avoid join?

mvc entity framework : login using a database

I have created a database in Microsoft sql server express. I need to be able to login on Mvc 2 app, using my database ( not the one existing on AcountController meaning MembershipService )
I just need to replace MemeberAhipService with my database. How can I do that ( i'm using entity framework code first ) . I don't need to create a model in visual studio. I have the usermodel, userContext: Db . I think i need repository also. Can anyone show me an example, of tell me the steps ?
You can create your own MembershipService.
Example:
New MembershipService.cs (or whatever you want)
public class MembershipService
{
public bool IsUserValid(string username, string password)
{
var db = new DatabaseContext();
var user = db.GetUser(username, password);
// Or however you want to get your data, via Context or Repository
return (user != null);
}
}
New FormsClass.cs
public class FormService
{
public void SignIn(string username, List&ltstring> roles)
{
FormsAuthenticationTicket authTicket = new
FormsAuthenticationTicket(1, // Version
username, // Username
DateTime.Now, // Creation
DateTime.Now.AddMinutes(30), // Expiration
false, // Persistent
string.Join(",", roles.ToArray())); // Roles
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpContext.Current.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
GenericIdentity id = new GenericIdentity(username);
HttpContext.Current.User = new GenericPrincipal(id, roles.ToArray());
}
}
In Global.asax:
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
string encTicket = authCookie.Value;
if (!String.IsNullOrEmpty(encTicket))
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(encTicket);
FormsIdentity id = (FormsIdentity)Context.User.Identity;
var roles = ticket.UserData.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
GenericPrincipal prin = new GenericPrincipal(id, roles);
HttpContext.Current.User = prin;
}
}
}

Crystal report -- invalid log on parameter error

I have a crystal report which was working fine on my local machine but when I moved it to my server it's giving me a "Incorrect Log on parameters".
Code is below. It's called from a .net application
Dim CR As New ReportDocument
Dim str As String = Application.StartupPath
If PrintDialog1.ShowDialog() <> Windows.Forms.DialogResult.OK Then Exit Sub
CR.Load(Application.StartupPath & "\CR Reports\BookPickByConsignee.rpt")
CR.SetParameterValue("param_picknumber", Me.txtpickNumber.Text.Trim())
CR.DataSourceConnections.Item(0).SetConnection(Configuration.ConfigurationSettings.AppSettings("DatabaseServer").ToString(), Configuration.ConfigurationSettings.AppSettings("DatabaseName").ToString(), Configuration.ConfigurationSettings.AppSettings("UserName").ToString(), Configuration.ConfigurationSettings.AppSettings("Password").ToString())
'CR.DataSourceConnections.Item(0).SetLogon("sa", "pwd")
' CR.SetDatabaseLogon("sa", "pwd")
CR.PrintOptions.PrinterName = PrintDialog1.PrinterSettings.PrinterName
CR.PrintToPrinter(Me.txtCopies.Text, True, 1, 100)
CR.Close()
You can use the following code to apply certain connection details for a report at run time.
Sorry, code in c#.
Please use that method just after loading report rpt file, instead of CR.DataSourceConnections.Item(0).SetConnection and pass required connection details to method, it will work.
public static void CrystalReportLogOn(ReportDocument reportParameters,
string serverName,
string databaseName,
string userName,
string password)
{
TableLogOnInfo logOnInfo;
ReportDocument subRd;
Sections sects;
ReportObjects ros;
SubreportObject sro;
if (reportParameters == null)
{
throw new ArgumentNullException("reportParameters");
}
try
{
foreach (CrystalDecisions.CrystalReports.Engine.Table t in reportParameters.Database.Tables)
{
logOnInfo = t.LogOnInfo;
logOnInfo.ReportName = reportParameters.Name;
logOnInfo.ConnectionInfo.ServerName = serverName;
logOnInfo.ConnectionInfo.DatabaseName = databaseName;
logOnInfo.ConnectionInfo.UserID = userName;
logOnInfo.ConnectionInfo.Password = password;
logOnInfo.TableName = t.Name;
t.ApplyLogOnInfo(logOnInfo);
t.Location = t.Name;
}
}
catch
{
throw;
}
sects = reportParameters.ReportDefinition.Sections;
foreach (Section sect in sects)
{
ros = sect.ReportObjects;
foreach (ReportObject ro in ros)
{
if (ro.Kind == ReportObjectKind.SubreportObject)
{
sro = (SubreportObject)ro;
subRd = sro.OpenSubreport(sro.SubreportName);
try
{
foreach (CrystalDecisions.CrystalReports.Engine.Table t in subRd.Database.Tables)
{
logOnInfo = t.LogOnInfo;
logOnInfo.ReportName = reportParameters.Name;
logOnInfo.ConnectionInfo.ServerName = serverName;
logOnInfo.ConnectionInfo.DatabaseName = databaseName;
logOnInfo.ConnectionInfo.UserID = userName;
logOnInfo.ConnectionInfo.Password = password;
logOnInfo.TableName = t.Name;
t.ApplyLogOnInfo(logOnInfo);
}
}
catch
{
throw;
}
}
}
}
}

SMO: restoring to a different DB

I've read a dozen different blogs, as well as reading through the msdn examples and they just aren't working for me.
Ultimately what I'm trying to do is automate moving a DB from our production instance to our dev instance, or the other direction.
The approach I've taken is thus:
backup/restore to a temp DB
detach temp DB
copy mdf and ldf files to the other instance
reattach.
I'm stuck on 1 and I cannot understand why. Everything I've read claims this should be working.
NOTE: I've set dbName to the db I want to restore to. I have also set restore.Database = dbName, where restore is an instance of the Restore class in the smo namespace.
mdf.LogicalFileName = dbName;
mdf.PhysicalFileName = String.Format(#"{0}\{1}.mdf", server.Information.MasterDBPath, dbName);
ldf.LogicalFileName = dbName + "_log";
ldf.PhysicalFileName = String.Format(#"{0}\{1}.ldf", server.Information.MasterDBPath, dbName);
restore.RelocateFiles.Add(mdf);
restore.RelocateFiles.Add(ldf);
restore.SqlRestore(server);
This is the exception I'm getting:
The file 'D:\MSSQL.MIQ_Dev\MSSQL.2\MSSQL\Data\MIQDesign2Detach.mdf' cannot be overwritten. It is being used by database 'MIQDesignTest2'.
File 'MIQDesign' cannot be restored to 'D:\MSSQL.MIQ_Dev\MSSQL.2\MSSQL\Data\MIQDesign2Detach.mdf'. Use WITH MOVE to identify a valid location for the file.
The file 'D:\MSSQL.MIQ_Dev\MSSQL.2\MSSQL\Data\MIQDesign2Detach.ldf' cannot be overwritten. It is being used by database 'MIQDesignTest2'.
File 'MIQDesign_log' cannot be restored to 'D:\MSSQL.MIQ_Dev\MSSQL.2\MSSQL\Data\MIQDesign2Detach.ldf'. Use WITH MOVE to identify a valid location for the file.
Problems were identified while planning for the RESTORE statement. Previous messages provide details.
RESTORE DATABASE is terminating abnormally.
Why is this trying to overwrite the original mdf? Isn't the RelocateFiles stuff supposed to specify that you want it being saved to a different physical filename?
It is works.
public class DatabaseManager
{
public Action<int, string> OnSqlBackupPercentComplete;
public Action<int, string> OnSqlRestorePercentComplete;
public Action<SqlError> OnSqlBackupComplete;
public Action<SqlError> OnSqlRestoreComplete;
public bool IsConnected { get; private set; }
private ServerConnection _connection;
public void Connect(string userName, string password, string serverName, bool useInteratedLogin)
{
if (useInteratedLogin)
{
var sqlCon = new SqlConnection(string.Format("Data Source={0}; Integrated Security=True; Connection Timeout=5", serverName));
_connection = new ServerConnection(sqlCon);
_connection.Connect();
IsConnected = true;
}
else
{
_connection = new ServerConnection(serverName, userName, password);
_connection.ConnectTimeout = 5000;
_connection.Connect();
IsConnected = true;
}
}
public void BackupDatabase(string databaseName, string destinationPath)
{
var sqlServer = new Server(_connection);
databaseName = databaseName.Replace("[", "").Replace("]", "");
var sqlBackup = new Backup
{
Action = BackupActionType.Database,
BackupSetDescription = "ArchiveDataBase:" + DateTime.Now.ToShortDateString(),
BackupSetName = "Archive",
Database = databaseName
};
var deviceItem = new BackupDeviceItem(destinationPath, DeviceType.File);
sqlBackup.Initialize = true;
sqlBackup.Checksum = true;
sqlBackup.ContinueAfterError = true;
sqlBackup.Devices.Add(deviceItem);
sqlBackup.Incremental = false;
sqlBackup.ExpirationDate = DateTime.Now.AddDays(3);
sqlBackup.LogTruncation = BackupTruncateLogType.Truncate;
sqlBackup.PercentCompleteNotification = 10;
sqlBackup.PercentComplete += (sender, e) => OnSqlBackupPercentComplete(e.Percent, e.Message);
sqlBackup.Complete += (sender, e) => OnSqlBackupComplete(e.Error);
sqlBackup.FormatMedia = false;
sqlBackup.SqlBackup(sqlServer);
}
public DatabaseCollection GetDatabasesList()
{
if (IsConnected)
{
var sqlServer = new Server(_connection);
return sqlServer.Databases;
}
return null;
}
public void RestoreDatabase(string databaseName, string filePath)
{
var sqlServer = new Server(_connection);
databaseName = databaseName.Replace("[", "").Replace("]", "");
var sqlRestore = new Restore();
sqlRestore.PercentCompleteNotification = 10;
sqlRestore.PercentComplete += (sender, e) => OnSqlRestorePercentComplete(e.Percent, e.Message);
sqlRestore.Complete += (sender, e) => OnSqlRestoreComplete(e.Error);
var deviceItem = new BackupDeviceItem(filePath, DeviceType.File);
sqlRestore.Devices.Add(deviceItem);
sqlRestore.Database = databaseName;
DataTable dtFileList = sqlRestore.ReadFileList(sqlServer);
int lastIndexOf = dtFileList.Rows[1][1].ToString().LastIndexOf(#"\");
string physicalName = dtFileList.Rows[1][1].ToString().Substring(0, lastIndexOf + 1);
string dbLogicalName = dtFileList.Rows[0][0].ToString();
string dbPhysicalName = physicalName + databaseName + ".mdf";
string logLogicalName = dtFileList.Rows[1][0].ToString();
string logPhysicalName = physicalName + databaseName + "_log.ldf";
sqlRestore.RelocateFiles.Add(new RelocateFile(dbLogicalName, dbPhysicalName));
sqlRestore.RelocateFiles.Add(new RelocateFile(logLogicalName, logPhysicalName));
sqlServer.KillAllProcesses(sqlRestore.Database);
Database db = sqlServer.Databases[databaseName];
if (db != null)
{
db.DatabaseOptions.UserAccess = DatabaseUserAccess.Single;
db.Alter(TerminationClause.RollbackTransactionsImmediately);
sqlServer.DetachDatabase(sqlRestore.Database, false);
}
sqlRestore.Action = RestoreActionType.Database;
sqlRestore.ReplaceDatabase = true;
sqlRestore.SqlRestore(sqlServer);
db = sqlServer.Databases[databaseName];
db.SetOnline();
sqlServer.Refresh();
db.DatabaseOptions.UserAccess = DatabaseUserAccess.Multiple;
}
public void Disconnect()
{
if (IsConnected)
_connection.Disconnect();
IsConnected = false;
}
}
I ran into a similar problem and I found this solution to be quite helpful.
Take a look - http://www.eggheadcafe.com/software/aspnet/32188436/smorestore-database-name-change.aspx