How do Microsoft reports (RDL) query the data? - c#

I am not creating RDL from scratch so maybe this is a problem -- I work on already prepared files.
MSDN states that CommandText in RDL file can contain T-SQL query. Ok, this I understand, but what else it can contains?
I am asking because the phrasing clearly indicates you can put some other expression there
So if I understand correctly, I can look at RDL code (in Visual Studio, RMB on RDL file, "view code") and the interesting parts would be...?
DataSourceName -- this is a "link" to database via definitions of data sources
CommandText -- I thought this is the place to put query, like SELECT... but from what I see there are no queries used

Reporting service, loads the rdl file into it, and starts parsing and reading the command according to their sections like
data source, report params, etc.
gets the values of params (if any). start using the data source database connection. execute the query/ sp command. get the data, and store in seperate data fields which are also mentioned in rdl. binds their values with controls (text box, grid columns etc), if there is any expression written into it, execute them as well.
Generate the output (html/ pdf).
And there you Go.
I just tried to explain in short and simple words. you can check out msdn for complete detail.
Regards,
Mazhar Karimi

You can create reports manually and fill them with any data that you would like to.
Sth like:
ReportDataSource reportDataSource = new ReportDataSource();
reportViewer.Reset();
reportDataSource.Name = "DataSetOdczyty_klienci_adresy";
reportDataSource.Value = klienciadresyBindingSource;
reportViewer.LocalReport.DataSources.Add(reportDataSource);
reportViewer.LocalReport.ReportEmbeddedResource = "Wodociagi.Reports.ReportListaKlientow.rdlc";

You can open the report file *.rdl with an XML editor like Notepad++. Then, search for <DataSets> and you will find the datasets used in the report.
The field names of each data set are in the <Fields> section
In the <Query> section of each data set you can find <CommandText> and <QueryParameters> as shown in the example below
Example:
<Query>
<DataSourceName>MyDataSource</DataSourceName>
<CommandType>StoredProcedure</CommandType>
<CommandText>usp_QueryCustomers</CommandText>
<QueryParameters>
<QueryParameter Name="#CustomerId">
<Value>=Parameters!PersSysId.Value</Value>
</QueryParameter>
<QueryParameter Name="#RowsCnt">
<Value>=Parameters!RowsCnt.Value</Value>
</QueryParameter>
</QueryParameters>
</Query>
I didn't find a way to see that in Visual Studio's report editor easily. Maybe the bounty I have started helps here (does someone like to earn the 50 reputation points)?

Initially, I was not sure why both the OP and #Matt are reading the XML directly instead of editing the query in Visual Studio (I only resort to that in extreme cases). But now I think you might have failed victims of the missing "Report Data" pane.
Open the report in Visual Studio BIDS like normally, then from View menu select "Report Data". If it's not there, click on the report canvas anywhere, then it should appear. In the "Report Data" pane that will appear, you're interested in Data Sources (where's the data coming from?) and Datasets (what are the queries, parameters, expressions?).

Related

Sorting by FormulaField in Crystal Reports

I've begun the task of bringing our CR to the 21st century. The templates were created more than 10 years ago, as well as the report generator application written in Visual Basic that allows a user to pick different options before they click a button for generating a report.
So far the process hasn't been too bad but I've stumbled upon something that I can't figure out.
In VB, there's a line of code that sorts the report by a database table field:
Report.RecordSortFields.Add Report.Database.Tables(1).fields.GetItemByName("Name"), crAscendingOrder
I've successfully got that same logic working using the lines below
DatabaseFieldDefinition databaseFieldDefinition = Report.Database.Tables["Bureau"].Fields["Name"];
SortField sortField = Report.DataDefinition.SortFields[0];
sortField.Field = databaseFieldDefinition;
sortField.SortDirection = SortDirection.AscendingOrder;
The other type of sorting is what I'm struggling with. The problem is if that DataDefinition only contains a single SortField using a database tables field, I can't seem to make it order using a formula field. If you iterate through the formula fields you can see multiple fields like #Name, #XX, however if you look in the sort field it looks like it's specifying just a table like 'Assets.Name'
In the original code, this was done simply using the this VB line of code:
Report.RecordSortFields.Add Report.FormulaFields.GetItemByName("AssetName"), crAscendingOrder
For report files that already have a sort field with an #XXX, it works because I'm just replacing the SortField with this new FormulaDefinition that I've got from the below code (that also uses the #XXX), however if the sort field is only using a 'Table.Field' it doesn't work
Report.DataDefinition.FormulaFields["AssetName"];
My obvious first guess is that I need to modify the report file to get this working, however the report files are still allowing sorting via formulafield even in our old VB app, meaning if they could do it back 10+ years ago in vb I should be able to do it in C# without modifying the report.

SQL Server database truncated a big base64 string [duplicate]

How do you view ALL text from an NTEXT or NVARCHAR(max) in SQL Server Management Studio? By default, it only seems to return the first few hundred characters (255?) but sometimes I just want a quick way of viewing the whole field, without having to write a program to do it. Even SSMS 2012 still has this problem :(
I was able to get the full text (99,208 chars) out of a NVARCHAR(MAX) column by selecting (Results To Grid) just that column and then right-clicking on it and then saving the result as a CSV file. To view the result open the CSV file with a text editor (NOT Excel). Funny enough, when I tried to run the same query, but having Results to File enabled, the output was truncated using the Results to Text limit.
The work-around that #MartinSmith described as a comment to the (currently) accepted answer didn't work for me (got an error when trying to view the full XML result complaining about "The '[' character, hexadecimal value 0x5B, cannot be included in a name").
Quick trick-
SELECT CAST('<A><![CDATA[' + CAST(LogInfo as nvarchar(max)) + ']]></A>' AS xml)
FROM Logs
WHERE IDLog = 904862629
In newer versions of SSMS it can be configured in the (Query/Query Options/Results/Grid/Maximum Characters Retrieved) menu:
Old versions of SSMS
Options (Query Results/SQL Server/Results to Grid Page)
To change the options for the current queries, click Query Options on the Query menu, or right-click in the SQL Server Query window and select Query Options.
...
Maximum Characters Retrieved
Enter a number from 1 through 65535 to specify the maximum number of characters that will be displayed in each cell.
Maximum is, as you see, 64k. The default is much smaller.
BTW Results to Text has even more drastic limitation:
Maximum number of characters displayed in each column
This value defaults to 256. Increase this value to display larger result sets without truncation. The maximum value is 8,192.
I have written an add-in for SSMS and this problem is fixed there. You can use one of 2 ways:
you can use "Copy current cell 1:1" to copy original cell data to clipboard:
http://www.ssmsboost.com/Features/ssms-add-in-copy-results-grid-cell-contents-line-with-breaks
Or, alternatively, you can open cell contents in external text editor (notepad++ or notepad) using "Cell visualizers" feature: http://www.ssmsboost.com/Features/ssms-add-in-results-grid-visualizers
(feature allows to open contents of field in any external application, so if you know that it is text - you use text editor to open it. If contents is binary data with picture - you select view as picture. Sample below shows opening a picture):
Return data as XML
SELECT CONVERT(XML, [Data]) AS [Value]
FROM [dbo].[FormData]
WHERE [UID] LIKE '{my-uid}'
Make sure you set a reasonable limit in the SSMS options window, depending on the result you're expecting.
This will work if the text you're returning doesn't contain unencoded characters like & instead of & that will cause the XML conversion to fail.
Returning data using PowerShell
For this you will need the PowerShell SQL Server module installed on the machine on which you'll be running the command.
If you're all set up, configure and run the following script:
Invoke-Sqlcmd -Query "SELECT [Data] FROM [dbo].[FormData] WHERE [UID] LIKE '{my-uid}'" -ServerInstance "database-server-name" -Database "database-name" -Username "user" -Password "password" -MaxCharLength 10000000 | Out-File -filePath "C:\db_data.txt"
Make sure you set the -MaxCharLength parameter to a value that suits your needs.
I was successful with this method today. It's similar to the other answers in that it also converts the contents to XML, just using a different method. As I didn't see FOR XML PATH mentioned amongst the answers, I thought I'd add it for completeness:
SELECT [COL_NVARCHAR_MAX]
FROM [SOME_TABLE]
FOR XML PATH(''), ROOT('ROOT')
This will deliver a valid XML containing the contents of all rows, nested in an outer <ROOT></ROOT> element. The contents of the individual rows will each be contained within an element that, for this example, is called <COL_NVARCHAR_MAX>. The name of that can be changed using an alias via AS.
Special characters like &, < or > or similar will be converted to their respective entities. So you may have to convert <, > and & back to their original character, depending on what you need to do with the result.
EDIT
I just realized that CDATA can be specified using FOR XML too. I find it a bit cumbersome though. This would do it:
SELECT 1 as tag, 0 as parent, [COL_NVARCHAR_MAX] as [COL_NVARCHAR_MAX!1!!CDATA]
FROM [SOME_TABLE]
FOR XML EXPLICIT, ROOT('ROOT')
PowerShell Alternative
This is an old post and I read through the answers. Still, I found it a bit too painful to output multi-line large text fields unaltered from SSMS. I ended up writing a small C# program for my needs, but got to thinking it could probably be done using the command line. Turns out, it is fairly easy to do so with PowerShell.
Start by installing the SqlServer module from an administrative PowerShell.
Install-Module -Name SqlServer
Use Invoke-Sqlcmd to run your query:
$Rows = Invoke-Sqlcmd -Query "select BigColumn from SomeTable where Id = 123" `
-MaxCharLength 2147483647 -ConnectionString $ConnectionString
This will return an array of rows that you can output to the console as follows:
$Rows[0].BigColumn
Or output to a file as follows:
$Rows[0].BigColumn | Out-File -FilePath .\output.txt -Encoding UTF8
The result is a beautiful un-truncated text written to a file for viewing/editing. I am sure there is a similar command to save back the text to SQL Server, although that seems like a different question.
EDIT: It turns out that there was an answer by #dvlsc that described this approach as a secondary solution. I think because it was listed as a secondary answer, is the reason I missed it in the first place. I am going to leave my answer which focuses on the PowerShell approach, but wanted to at least give credit where it was due.
If you only have to view it, I've used this:
print cast(dbo.f_functiondeliveringbigformattedtext(seed) as text)
The end result is that I get line feeds and all the content in the messages window of SMSS.
Of course, it only allows for a single cell - if you want to do a single cell from a number of rows, you could do this:
declare #T varchar(max)=''
select #T=#T
+ isnull(dbo.f_functiondeliveringbigformattedtext(x.a),'NOTHINGFOUND!')
+ replicate(char(13),4)
from x -- table containing multiple rows and a value in column a
print #T
I use this to validate JSON strings generated by SQL code. Too hard to read otherwise!
Use visual studio code with sql server plugin. Super usefull for jsons
Alternative 1: Right Click to copy cell and Paste into Text Editor (hopefully with utf-8 support)
Alternative 2: Right click and export to CSV File
Alternative 3: Use SUBSTRING function to visualize parts of the column. Example:
SELECT SUBSTRING(fileXml,2200,200) FROM mytable WHERE id=123456
The easiest way to quickly view large varchar/text column:
declare #t varchar(max)
select #t = long_column from table
print #t

How to remove Database fields from Crystal report programmatically [duplicate]

I have a section in a Crystal Report that I want to suppress. I need to suppress it if there are 0 rows in a particular table in the dataset I am using. How would I do this? The Record Number special field provided appears to be an internal count of records in the report, and does not relate to the rows in the underlying data table.
I am creating the report from C#, but I cannot suppress the section from the code (it doesn't fit the project structure) - I must be able to do it from the report itself. The table concerned is definitely being passed to the report in the dataset, but it contains 0 rows. There must be a way to establish this inside the report itself.....
Can anyone please point me in the right direction?
In the Crystal Reports designer, view the properties of your section and there should be an option to Suppress, which you can give it a formula to return the appropriate boolean value.
You could then use the Count() function within that formula and (I believe) you can pass the name of your dataset to the Count() function to get the number of rows in that dataset.
I did the same thing on a complex report about 3 months ago but I don't have access to the report any more having changed jobs so I'm sorry I cannot be more specific, but hoepfully this gives you a starting point.
Just had a quick Google - try this.
If the section does only contain database fields and f.e. no text fields, then you could use the setting "Suppress Blank Section" in the "Section Export" (rightclick section) for that section.
As an alternative you could use the following formula in the "Suppress" in the "Section Export" for that section:
IsNull({table.field})
"{table.field}" is one of the fields in the dataset.
Hope this helps.
Go to "Section Expert" and click "Supress (No Drill-Down)" and try adding this:
IF {"DragYourFieldHere"} = "" then true else false
Create one dummy group,check on its header for each page,add the header in the group header of the dummy group.

Using a BindingSource to link a DataSet to a DataGridView, but there's no data

This is my first time working with DataSets and BindingSources, so please be gentle on me.
As part of a more complicated reporting system (I've distilled it down to a basic incarnation, but it still won't run correctly), I'm trying to pull data from a database using a DataSet problematically (that is, not set up via the designer). Here is the code I have so far:
// pull the data set
var dsReportData = new Reports2.ReportTest2();
dsReportData.BeginInit();
dsReportData.SchemaSerializationMode = SchemaSerializationMode.IncludeSchema;
// bind tha data set
BindingSource bsReportBinding = new BindingSource();
((ISupportInitialize)bsReportBinding).BeginInit();
bsReportBinding.DataMember = dsReportData.Tables[0].TableName;
bsReportBinding.DataSource = dsReportData;
bsReportBinding.ResetBindings(true);
// test this stuff
dgvTester.DataSource = bsReportBinding;
dsReportData.EndInit();
((ISupportInitialize)bsReportBinding).EndInit();
I based this on the code I saw in a .designer.cs file after setting up binding through the designer. dgvTester is just a DataGridView with the default properties created in the designer.
The ReportTest2 dataset has just one TableAdapter in it, added via designer.
Now, if I went to Data -> Preview Data in VS and previewed the ReportTest2.payments.Fill,GetData () object, it returns data just fine, same as if I ran the query I used to crate the TableAdapter in SQL Server Management Studio.
However, running the actual code results in the DataGridView getting the column names from the query result, but not the actual data. The debugger reveals that dsReportData.payments.Rows.Count == 0 (and that, yes, dsReportData.Tables[0] is payments).
I ultimately intend to use the BindingSource to provide data to a ReportViewer, but first things first is making sure there's no problems with retrieving the data before going onto debug the report.
Hopefully I'm missing something obvious here. I hope so...
Figured it out after some trial and error. This is the part I was missing:
var TableAdapter = new Reports2.ReportTest2TableAdapters.paymentsTableAdapter();
TableAdapter.Fill(dsReportData.payments);
I didn't see it in the code I was referencing because the designer snuck it into the .cs file instead of the .designer.cs file. This made the data appear.

How to create report (RDLC) without database?

Problem
When you create a report (RDLC) the datasource seems to be only this or that database. Is there any way to convince VS to establish a link to memory data source? Something similar to WPF databinding.
The issue is, I would like to create a report with just a few data (entered by user), the whole point is layout, I don't have massive amount of data. So installing DB, writing data to DB, and then fetching them just to show the report is huge overkill.
So, I am looking for ability to create a report from memory data.
Background
I would like to design a layout, add images, set styles, font colors, etc. and add no more than few parameters like "first name", "last name" (of user) and "text". User would enter those 3 values, get a flyer and print it X times.
The layout has to be exact -- starting from paper size, the placement of images, size of fonts, etc.
Maybe there are better solutions than RDLC but it is built-in engine, and no matter how I search it always pops out in search results.
The datasource for an RDLC report can be anything that implements IEnumerable. If it is an enumeration of objects, then the properties on the object become fields in the report.
The thing about reports is they have their own internal notion of what the dataset is. At design time you need to provide the report designer with a dataset to work with. The report ingests that dataset internally and it is used to design the report. The reality is the report itself doesn't care about the actual dataset. It only cares about its schema. However, at runtime the objects you provide to satisfy that dataset can come from anywhere, as long as they satisfy that same schema.
I have a little blog post from back in my MS days that shows a trick on how to get good design time support, and then at runtime provide the report with any data you want:
http://blogs.msdn.com/b/magreer/archive/2008/10/16/setting-the-datasource-for-a-report-at-runtime.aspx
update Microsoft has since deleted my blog, but I found it in the wayback machine
https://web.archive.org/web/20160204041848/http://blogs.msdn.com/b/magreer/archive/2008/10/16/setting-the-datasource-for-a-report-at-runtime.aspx
I recently wrote a blog post on creating a reporting assembly and using it in a project. My reports accept a list of my classes as a datasource and dont read from the DB themselves.
If you have a look here:
http://wraithnath.blogspot.com/2011/02/visual-studio-2010-report-viewer-object.html
it should help. Basically you create a class library containing the datasources as VS 2010 has a real problem detecting object datasources. It works like 20% of the time which is why i decided to do it this way.
N
You can definitely bind to DataTables. Since you can create DataTables by hand, that's one way to do this without a database.
Here's an example where we programmatically load an RDLC control in order to render a PDF, using DataTables:
Dim Viewer As New ReportViewer
Viewer.LocalReport.ReportPath = "Physicians\Patients\OrderPlacement\DownloadRx\RxPdf.rdlc"
Me.LoadReport(orderID, Viewer)
Dim Renderer As New Code.Reporting.RenderToPDF
Renderer.Save(Viewer, FileFullPath)
And here are the contents of LoadReport:
Private Sub LoadReport(ByVal orderID As Integer, ByVal viewer As ReportViewer)
'This is adapted from here: http://www.codeproject.com/KB/reporting-services/RDLC_and_DataSet.aspx
'--Setup
viewer.LocalReport.DataSources.Clear()
viewer.LocalReport.EnableHyperlinks = True
'--Configure DataSources
Dim DocumentData As New RxDocumentData(orderID)
Me.SetupRxPdfDataSourceHeader(DocumentData, viewer)
Me.SetupRxPdfDataSourceMetrics(DocumentData, viewer)
Me.SetupRxPdfDataSourceOrderHeader(DocumentData, viewer)
Me.SetupRxPdfDataSourceOrderItems(DocumentData, viewer)
Me.SetupRxPdfDataSourceChainOfCustody(DocumentData, viewer)
Me.SetupRxPdfDataSourcePreTreatmentWorkupOrderTags(DocumentData, viewer)
Me.SetupRxPdfDataSourceTakeHomeMedicationsOrderTags(DocumentData, viewer)
viewer.LocalReport.Refresh()
End Sub
And here's one of those little configuration methods:
Private Sub SetupRxPdfDataSourceHeader(ByVal data As RxDocumentData, ByVal viewer As ReportViewer)
Dim Dset_Header As New ReportDataSource("Dset_Header", data.HeaderDataTable)
viewer.LocalReport.DataSources.Add(Dset_Header)
End Sub
data.HeaderDataTable is just a strongly typed DataTable that we create programmatically and put data into by hand.
There's nothing special about the DataTable, but getting to the point where this code was functional probably took a solid week. Hope this helps.
You can manually create a DataTable object, populate the Columns collection in there, then call NewRow(). Take the result of that and fill the fields, then pass it to Rows.Add(). That's what I've been doing (really don't like rdlc, it's so slow and clunky compared to html).
Return a list of your business objects and add it as the data source:
ReportViewer.LocalReport.DataSources.Add(new ReportDataSource("Report", new List<ReportDto> { new ReportDto(businessObj) }));
ReportDto is a wrapper for your business object where all formatting, concatenations and other report related modifications are done. It emits only the properties you need for the report.
Then go to add data set and pick the ReportDto's namespace as the data source and pick ReportDto as the dataset. Now all the properties you have included in ReportDto will be available in the designer.

Categories