I have come across a challenging requirement for Reports and Printing of reports. The requirement is : Create a report (lets say 5 pages), each page should be saved in different files with providing the filename dynamically (using record id on that page) through the code.
Currently, I tried with Access and VBA, I could get the report of X pages, but fail to save each page of the report in separate files. How do I accomplish this ?
Can any other technology help me achieve this goal - maybe programming in C# or Java help me? I've been stuck on this for 3 days on this.
Thanks
My Access Code and the problem :
Private Sub Report_Click()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim MyFilename As String
Dim MyPath As String
Dim temp As String
Set db = CurrentDb
MyPath = "c:\temp\"
Dim stremp As String
stremp = "select distinct(empno) from query2"
Set rs = db.OpenRecordset(stremp)
Do While Not rs.EOF
temp = rs("Empno")
MyFilename = rs("EMPNO") & ".PDF"
DoCmd.OpenReport "FORM", acViewReport, "EMPNO" = " & temp"
'DoCmd.OpenReport "form", acViewPreview, , "empno", acWindowNormal
DoCmd.OutputTo acOutputReport, "", acFormatPDF, MyPath & MyFilename
'do.cmd.outputto
DoCmd.Close acReport, "FORM"
DoEvents
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
The recordset has 5 records i.e. 5 pages. It prints 5 times 5 pages i.e. for Record1 I get all 5 recrods, Record2 - all 5 records & so on. Instead I should create only 1 for Record1, 1 for Record2 and so on.
Can anyone help me know where my code is wrong/improper.
Thanks
you can split task to:
generate full report as one file
store every page of report as different files.
If you already complete first part, and if you can store your report as pdf file, for second part i can suggest to use iText. It is java library, but has port to c# too.
Small example:
String folder = "/home/user/report/";
InputStream is = new FileInputStream(folder + "test.pdf");
PdfReader reader = new PdfReader(is);
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
File tmp = new File(folder + "out" + i +".pdf");
FileOutputStream outStream = new FileOutputStream(tmp);
Document pdDoc = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(pdDoc, outStream);
pdDoc.open();
PdfContentByte cb = writer.getDirectContent();
PdfImportedPage page = writer.getImportedPage(reader, i);
pdDoc.newPage();
cb.addTemplate(page, 0, 0);
pdDoc.close();
}
Can you help me know, why my code of Access doesn't do the job.
This statement has problems:
DoCmd.OpenReport "FORM", acViewReport, "EMPNO" = " & temp"
The third argument of DoCmd.OpenReport is [FilterName] which is "A string expression that's the valid name of a query in the current database." Unfortunately,
"EMPNO" = " & temp"
is a boolean expression that will always be False because the two strings are not equal. I think you had something more like this in mind:
DoCmd.OpenReport "FORM", acViewReport, , "EMPNO = " & temp
where the fourth argument, [WhereCondition], is "A string expression that's a valid SQL WHERE clause without the word WHERE."
Related
I am uploading a file to \temp\ but I want to access it through a hyperlink in a given column inside Access. I can successfully paste the string to the hyperlink field, but there´s no link between the string and the file itself.
I tried to copy paste a website address from a browser to Access, surprisingly the hyperlink is pasted along with the "string"
//upload arquivo
string conexaoAccess2 = ConfigurationManager.ConnectionStrings["conexaoAccess"].ToString();
using (OleDbConnection conexaodb1 = new OleDbConnection(conexaoAccess2))
{
conexaodb1.Open();
Random r = new Random();
int n = r.Next();
// pega somente nome
string[] f = camArq.Split('\\');
string fn = f[(f.Length) - 1];
string fullDest = #"C:\temp\" + nomeArqnoExt + n + fileExtension0;
string q = "UPDATE tbl_reg SET Campo1 = #campo WHERE nome_user = #nome1";
//copia arquivo para a pasta destino
File.Copy(camArq, fullDest, true);
//to save to the database
OleDbCommand cmd = new OleDbCommand(q, conexaodb1);
var parCamp = cmd.CreateParameter();
parCamp.ParameterName = "campo";
parCamp.DbType = DbType.String;
parCamp.Value = fullDest;
cmd.Parameters.Add(parCamp);
var parNome1 = cmd.CreateParameter();
parNome1.ParameterName = "nome1";
parNome1.DbType = DbType.String;
parNome1.Value = mdl.nome;
cmd.Parameters.Add(parNome1);
cmd.ExecuteNonQuery();
}
I expect the string to be copied as an hyperlink, nevertheless, there´s no DbType that assumes this type of data, is there? The actual results are: I can successfully paste the file path to the field, but the field contains no hyperlink to anything whatsoever:
Access Hyperlink type field requires value that is composed of 3 parts separated by # character: displaytext#path#subreference. Options:
If using Hyperlink type field in Access table design, include # characters in string to save.
Just use a text field to save path string without # characters then use FollowHyperlink method in code or format string to hyperlink structure with concatenation expression: "#" & [fieldname] & "#" - calculate in query or textbox ControlSource and set textbox IsHyperlink property to yes.
I have a list of about 350 music files that I store in an sqlite table. If new files get added they are added to the db. So I have a query to check if the path of the file is in the table and if not then insert it. However 3 files never match the query even though they are in the table! Therefore they are added over and over each time I start my app.
I am using SQLite for Universal Windows Platform & SQLite.Net-PCL packages for the sql content. File is my custom class that stores some strings and other file properties from each file.
//database creation on first app launch
using (var db = DbConnection)
{
var Trackdb = db.CreateTable<Query>();
}
//where I scan all files and add to db if not already there
var dbconn = DbConnection;
foreach (File file in FileList)
{
var existingfile = dbconn.Query<Track>("select * from File where Path = '" + file .Path.Replace("'", "''") + "'").FirstOrDefault();
if (existingtrack == null)
{
file.ID = dbconn.Insert(file);
Debug.WriteLine(file.Path + " was added to db");
}
}
The output everytime, from what I see there might be 2 characters which could cause this, but why? "–" vs "-" and "ë" vs "e". Is sqlite not equipped to handle these characters or is my query not robust enough? The insert statement which works fine, leading me to believe it accepts these characters as it displays my my app fine.
"C:\Data\Users\Public\Music\David Guetta & Avicii – Sunshine.mp3 was added to db"
"C:\Data\Users\Public\Music\Gotye - Somebody That I Used To Know (Tiësto Remix).mp3 was added to db"
"C:\Data\Users\Public\Music\Lana Del Rey – Summertime Sadness (Cedric Gervais Remix).mp3 was added to db"
edit: solved by chue x
var existingfile = dbconn.Query<File>("SELECT * FROM Track WHERE Path = ?", file.Path.Replace("'", "''")).FirstOrDefault();
solved by chue x
var existingfile = dbconn.Query<File>("SELECT * FROM File WHERE Path = ?", file.Path.Replace("'", "''")).FirstOrDefault();
Greetings from Appdev (i'm new to Crystall Report)
I was Creating a web application which will contains a crystal report.
My Requirement is:
The report should be displayed Based on the value (textbox in web form) which is given in textbox.
Eg:
if Textbox value = 2 means only the item which has id 2 should only get display.
My crystal report has 3 sub Reports like cheque,Party(which also contains values from other table called voucher) and finally bank.
these 4 tables are linked by 1 common field called id.
need to know how to pass parameter to crystall report.
How to display the result only once (my code display same result twice)
this is how i bind the crystal report using parameters from .cs file in c#
public void LoadTransReceipt()
{
string Date = "";
string Sql = "SELECT tREC_NUPKId as ID from TB_TransReceipt where tREC_VCVoucherNo='" + TXTVou.Text.Trim() + "' and tREC_NUIsActive=1";
SqlDataReader rdr = mobjGenlib.objDBLib.ExecuteQueryReader(Sql.ToString());
while (rdr.Read())
{
Session["ID"] = rdr.GetValue(0).ToString();
}
rdr.Close();
if (!string.IsNullOrEmpty(Session["ID"] as string))
{
if (Session["Date"] != null)
{
Date = mobjGenlib.ConvertString(Session["Date"]);
}
reportPath = GetReportPath("ReceiptReport.rpt");
CRReport = new ReportDocument();
CRReport.Load(reportPath);
CrystalReportViewer1.ReportSource = CRReport;
AddParameterToReport("IDP", Session["ID"].ToString());
AddParameterToReport("ActiveP", 1);
AddParameterToReport("IDB", Session["ID"].ToString());
AddParameterToReport("ActiveB", 1);
AddParameterToReport("IDC", Session["ID"].ToString());
AddParameterToReport("ActiveC", 1);
// ConnectionInfo connectionInfo = ConnInfo();
ConnectionInfo objConnInfo = new ConnectionInfo();
objConnInfo.DatabaseName = "Demo";
objConnInfo.UserID = "aa";
objConnInfo.Password = "aaaa";
objConnInfo.ServerName = "HOME-PC\\SQLEXPRESS";
SetDBLogonForReport(objConnInfo, CRReport);
SetDataSetForMultipleSubReport(objConnInfo, CRReport);
}
}
but when i execute the code it displaying all data's available in table with double time like shown below
can any one help me to solve this issue
Thanks in advance
getting error as
" **
Specified argument was out of the range of valid values
**"
From Field Explorer in the report right click add new parameter, then in code behind you have to set the value of the parameter like:
CRReport.SetParameterValue("#Parameter", TXTVou.Text)
You can prevent the duplication by add the word DISTINCT to your Query like:
"SELECT DISTINCT tREC_NUPKId as ID from TB_TransReceipt where tREC_VCVoucherNo='" + TXTVou.Text + "' and tREC_NUIsActive=1"
or You can prevent the duplication by (Suppress If Duplicated) property in the field
I'm creating an application that loads data from SQL Database once a day and saves it into a text file.
The main table is a "Transactions" table, which holds data about all transactions made on that day. One of the columns represents a middle-man call sign.
My program saves the data in a DataTable first and then with a StringBuilder I give it the proper form and finally save it into a text file with StreamWriter.
My question is, how or on which stage of the process can I distinguish one table entry from another. I want to create two files: one with transactions made by middle-man A and B.
This is my code so far:
// Query for Data
row = new SqlDataAdapter("SELECT [MSISDN], [Amount], [Transaction_ID], POS.[Name], MNO.[Call Sign] FROM"
+ "[Transactions] join [POS] "
+ "on Transactions.POS_ID = POS.idPOS "
+ "join [MNO] on Transactions.MNO_ID = MNO.idMNO "
+ "where [Status] = '1'", con);
row.Fill(Row);
// Save Data in StringBuilder
for (int i = 0; i < Row.Rows.Count; i++)
{
sb.Append(Row.Rows[i].ItemArray[0].ToString()).Append(",");
double amount = Convert.ToDouble(Row.Rows[i].ItemArray[1].ToString());
sb.Append(Math.Round(amount, 2).ToString().Replace(",", ".")).Append(",");
sb.Append(Row.Rows[i].ItemArray[2].ToString()).Append(",");
sb.Append(Row.Rows[i].ItemArray[3].ToString()).Append(",");
sb.Append(Row.Rows[i].ItemArray[4].ToString()).Append(",").Append(Environment.NewLine);
}
// Create a file from StringBuilder
mydocpath = #"C:\Transactions\" + fileDate.ToString(format) + ".txt";
FileStream fsOverwrite = new FileStream(mydocpath, FileMode.Create);
using (StreamWriter outfile = new StreamWriter(fsOverwrite))
{
outfile.WriteAsync(sb.ToString());
}
Hope I was clear enough. English isn't my strong side. As well as coding for what it seems...
One option.
Put all your data into a DataSet. And then do Xsl transformations against the ds.GetXml().
Here is kind of an example:
http://granadacoder.wordpress.com/2007/05/15/xml-to-xml-conversion/
But what I would do is eliminate the DataTable altogether. Use an IDataReader.
Loop over the data. Maybe do the original query as "Order By Middle-Man-Identifer", and then when the middleManIdentifer "makes a jump", close the previous file and write a new one.
Something like that.
You may be able to learn something from this demo:
http://granadacoder.wordpress.com/2009/01/27/bulk-insert-example-using-an-idatareader-to-strong-dataset-to-sql-server-xml/
Here is a couple of IDataReader helpers:
http://kalit-codesnippetsofnettechnology.blogspot.com/2009/05/write-textfile-from-sqldatareader.html
and
How to efficiently write to file from SQL datareader in c#?
Hi all I'm porting over my VBScript over to C#. And I ran into a problem that Active Directory properties retrieval is much slower in C#.
This is my incomplete C# code
foreach(string s in dictLast.Keys)
{
if(s.Contains("/"))
str = s.Insert(s.IndexOf('/'), "\\");
else
str = s;
dEntry = new DirectoryEntry("LDAP://" + str);
strUAC = dEntry.Properties["userAccountControl"].Value.ToString();
cmd.CommandText = "INSERT INTO [NOW](readTime) VALUES(\"" + test.Elapsed.Milliseconds.ToString() + "\")";
cmd.ExecuteNonQuery();
test.Reset();
test.Start();
}
If I comment out this line.
strUAC = dEntry.Properties["userAccountControl"].Value.ToString();
It runs at 11 secs. But if I don't, it runs at 2mins 35 secs. The number of records are 3700. On average each record runs at 50 secs. I'm using the Stopwatch Class.
My VBscript runs at only 39 secs (Using difference of Time). With each record either a 0 or 15 milliseconds. I'm using the difference of Timer().
Here's my VBscript
strAttributes = "displayName, pwdLastSet, whenCreated, whenChanged, userAccountControl"
For Each strUser In objList.Keys
prevTime = Timer()
strFilter = "(sAMAccountName=" & strUser & ")"
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
adoCommand.CommandText = strQuery
Set adoRecordset = adoCommand.Execute
On Error Resume Next
If (adoRecordset.Fields("displayName") = null) Then
strCN = "-"
Else
strCN = adoRecordset.Fields("displayName")
End If
If (Err.Number <> 0) Then
MsgBox(strUser)
End If
strCr8 = DateAdd("h", 8, adoRecordset.Fields("whenCreated"))
strUAC = adoRecordset.Fields("userAccountControl")
If (strUAC AND ADS_UF_DONT_EXPIRE_PASSWD) Then
strPW = "Never expires"
Else
If (TypeName(adoRecordset.Fields("pwdLastSet").Value) = "Object") Then
Set objDate = adoRecordset.Fields("pwdLastSet").Value
dtmPwdLastSet = Integer8Date(objDate, lngBias)
Else
dtmPwdLastSet = #1/1/1601#
End If
If (dtmPwdLastSet = #1/1/1601#) Then
strPW = "Must Change at Next Logon"
Else
strPW = DateAdd("d", sngMaxPwdAge, dtmPwdLastSet)
End If
End If
retTime = Timer() - prevTime
If (objList.Item(strUser) = #1/1/1601#) Then
Wscript.Echo strCN & ";" & strUser & ";" & strPW & ";" & strCr8 & ";" & ObjChange.Item(strUser) & ";0;" & strUAC & ";" & retTime
Else
Wscript.Echo strCN & ";" & strUser & ";" & strPW & ";" & strCr8 & ";" & ObjChange.Item(strUser) & ";" & objList.Item(strUser) & ";" & strUAC & ";" & retTime
End If
Next
Any ideas what's the problem?
Please tell me if I'm not giving enough information. Thank you.
DirectorySearcher way. 1 min 8 secs.
dEntry = new DirectoryEntry("LDAP://" + strDNSDomain);
string[] strAttr = {"userAccountControl"};
foreach(string s in dictLast.Keys)
{
if(s.Contains("/"))
str = s.Insert(s.IndexOf('/'), "\\");
else
str = s;
ds = new DirectorySearcher(de, "(sAMAccountName=" + s + ")", strAttr, SearchScope.Subtree);
ds.PropertiesToLoad.Add("userAccountControl");
SearchResult rs = ds.FindOne();
strUAC = rs.Properties["userAccountControl"][0].ToString();
cmd.CommandText = "INSERT INTO [NOW](readTime) VALUES(\"" + test.Elapsed.Milliseconds.ToString() + "\")";
cmd.ExecuteNonQuery();
test.Reset();
test.Start();
}
where strDNSDomain is the defaultNamingContext. I've tried with domain name but it runs worse, at 3 mins 30 secs.
Looking at someone else's code. Would there be a difference if we omit the domain part?
using (var LDAPConnection = new DirectoryEntry("LDAP://domain/dc=domain,dc=com", "username", "password"))
And just use "LDAP://dc=domain,dc=com" instead.
Work around. Instead of binding each user and getting the properties. I stored all the properties in the first search for lastLogon instead. And output using StreamWriter.
Both DirectoryEntry and ADOConnection use ADSI underlying. There shouldn't be any performance difference.
The only reason for the performance difference is that you are trying to retrieve two different sets of data.
In your VBScript, you are setting ""displayName, pwdLastSet, whenCreated, whenChanged, userAccountControl" to strAttributes. ADSI is going to load these five attributes back from AD only.
In your C# code, you didn't call the RefreshCache method to specify what attributes that you like to load. So, when you access DirectoryEntry.Properties, it automatically calls a RefreshCache() for you without passing in any attributes for you. By default, ADSI will return all non-constructed attributes to you (pretty much all attributes) if you don't specify what attributes to load.
Another problem is that in your VBscript, you run only one LDAP query while in your C# code, you are running many LDAP queries. Each of the DirectoryEntry.RefreshCache() is going to translate to one single LDAP query. So, if you are trying to access 1000 objects, you are going to run 1000 different LDAP queries.
Take a relational database analogy, in VBscript, you are running
SELECT * FROM USER_TABLE
In C# code, you are running multiple times of the following queries
SELECT * FROM USER_TABLE WHERE id = #id
Of course, the C# code will be slower.
To do similar thing in C# code, you should use DirectorySearcher instead of DirectoryEntry.
Similarly, you need to remember to specify DirectorySearcher.PropertiesToLoad in order to specify what attributes to return from a LDAP query. If you don't specify, it will return all non-constructed attributes to you again.
Here are couple of things you can do
Enable Audit log in the LDAP server and see how your requests are going through. Audit logs will show you how much time it is taking for each request from your application and how many connections are opened etc.
Use System.DirectoryServices.Protocols which can make Asynchronous calls to LDAP. Check this sample post. Another advantage of using this name space is that you can specify attributes.
Close connection properly.
use DirectorySearcher.PropertiesToLoad to load only required properties instead of all properties.
what i see from vbscript following is a bit closer .. copying from some project, kindly test
DirectoryEntry de = new DirectoryEntry("ldap://domainname");
DirectorySearcher deSearch = new DirectorySearcher();
deSearch.SearchRoot = de;
deSearch.Filter = "(&(ObjectCategory=user)(sAMAccountName="+strUser+"))";
deSearch.PropertiesToLoad.Add("displayName");
deSearch.PropertiesToLoad.Add("pwdLastSet");
deSearch.PropertiesToLoad.Add("whenCreated");
deSearch.PropertiesToLoad.Add("whenChanged");
deSearch.PropertiesToLoad.Add("userAccountControl);
deSearch.SearchScope = SearchScope.Subtree;
SearchResult sr = deSearch.FindOne();
This is the correct way to read the property:
If searchResult.Properties.Contains(PropertyName) Then
Return searchResult.Properties(PropertyName)(0).ToString()
Else
Return String.Empty
End If