I have an application developed in VB6 which I am migrating to .Net Framework 4.0. There is a report that works correctly in the original application but the migrated application does not work on the original application. As a special feature, this report changed at runtime attribute "location" in two tables (actually they are seen) used to generate the SQL with which the report is fed, but when "shooting" the reporete the changes in tables with the attribute "location" are not reflected, that I can display using the "SQL Server Profiler" tool:
objReportDocument.Database.Tables(0).Location = "NameReferenceTable""
My point is this: When the report was build, they used 5 database tables of the data base: Table1, Table2, Table3, Table4 and Table5. Later, in de data base, the tables Table1 and Table2 were deleted. The idea is that en run time a store procedure constructed Table1 and Table2 like temporary tables with the original name more any id string; this new data base tables must be used when the report are rise.
When you walk over the Tables array of the report (ReportDocument.DataBase.Tables(n)), for each table you can see two key properties: Name and Location. I understand than Location propertie indicates to Crystal Reports with which tables should work to build the reorts, this is true?
I have not much experience with Crystal Reports, I investigated two weeks why this error is generated without an answer ... I hope you can help me a bit, I really appreciate it.
regards,
Fabian.
I will provide a method that I use for our Crystal Reports objects in my application. This is just used to set the login information for the report (our reports use built-in security), but if I am understanding your problem correctly, then you should be able to add/modify this method to set the Location as well.
The properties used in the method below are:
Me.ConnectionInfo is type CrystalDecisions.Shared.ConnectionInfo
Me.LogOnInfo is type CrystalDecisions.Shared.TableLogOnInfo
Me.Report is type CrystalDecisions.CrystalReports.Engine.ReportDocument
Also, g_strDb, g_strServer, and g_strMirror are some Strings whose value is irrelevant.
One thing I have found working with Crystal Reports in .NET, is that you need to set properties at the Table level, as you can see in the method below. Hopefully this helps you with your issue.
''' <summary>
''' Apply the database connection info to all tables recursively.
''' </summary>
''' <param name="crxRpt">The report document (or subreport) to apply connection info.</param>
Private Sub SetConnectionInfo(ByVal crxRpt As ReportDocument)
Dim reportObject As ReportObject
Dim subReportObject As SubreportObject
Dim section As Section
Dim t As Table
For Each t In crxRpt.Database.Tables
' if the DatabaseName in the report is <special db name>,
' we need to make sure to set the DatabaseName to the environment
' that the user is currently connected to in order to be able to
' pull the correct information for the report
If t.LogOnInfo.ConnectionInfo.DatabaseName = "<special db name>" Then
Me.ConnectionInfo.DatabaseName = g_strDb
Else
Me.ConnectionInfo.DatabaseName = t.LogOnInfo.ConnectionInfo.DatabaseName
End If
' only ApplyLogOnInfo for tables that are being pulled from the SQL
' server, this avoids problems that arise with reports that are
' created using field definition files
If t.LogOnInfo.ConnectionInfo.ServerName = g_strServer OrElse t.LogOnInfo.ConnectionInfo.ServerName = g_strMirror Then
t.ApplyLogOnInfo(Me.LogOnInfo)
End If
Next t
For Each section In crxRpt.ReportDefinition.Sections
For Each reportObject In section.ReportObjects
If reportObject.Kind = ReportObjectKind.SubreportObject Then
subReportObject = CType(reportObject, CrystalDecisions.CrystalReports.Engine.SubreportObject)
SetConnectionInfo(subReportObject.OpenSubreport(subReportObject.SubreportName))
End If
Next reportObject
Next section
End Sub
The above method is called from a setup method:
''' <summary>
''' Initialize the database connection info.
''' </summary>
Public Sub SetUpReport()
Me.LogOnInfo = New TableLogOnInfo
Me.ConnectionInfo.UserID = conUID
Me.ConnectionInfo.Password = conPWD
Me.ConnectionInfo.ServerName = g_strServer
Me.ConnectionInfo.DatabaseName = g_strDb
Me.SetConnectionInfo(Me.Report)
End Sub
And SetUpReport() is called any time we need to display/print the report.
Well, finally find the solution...
In my conection to BD use ODBC, the associate user to this conection no had a schema associate in the BD, then when the store procedure created the temporaly tables there are creates below the shchema bdo, but when crystal reports rise the report (used my ODBC with the associate user) no found the temporaly tables. So I associated a scheemma to the user used in my ODBC.
My original reports are old, then I had to open each one in VS2012, overwrite the report to update the format and test in Main Report Preview.
Related
I'm a bit dumbfounded here. Most of the tutorials I've seen around create a report using the wizard or a built-in (or ready-made) dataset. I build my dataset using queries in runtime so I'm not too sure how to adopt the ones I've seen so far.
Usually, when I create a report, it's a one record report and fields in the RDLC file can easily be populated using parameters. The one I'm trying to do below however works similarly to making a SELECT query. So here's what I'm trying to do, I'm trying to make a report that shows up like so:
Status: Approved
PID | Name | Address
1 | Name 1 | Address 1
2 | Name 2 | Address 2
===========================
Status: Denied
PID | Name | Address
3 | Name 3 | Address 3
4 | Name 4 | Address 4
I have several questions with this:
My RDLC reports are stored in a "\Reports" folder inside the folder with the .vb/.resx files. When I refer to it's using Application.StartupPath & "\Reports\myReport.rdlc", it can't find it there (obviously). Is there a way for me to embed the report files to the program (ie: use a relative folder name, where should I place the RDLC folder/file)? I don't think I should transfer the RDLC files to the Debug folder just to make this work (hence the full directory listing).
What's a good approach to take in trying to create a report using the code above? I was thinking that if I were to loop along my dataset and pass the values from there to the RDLC file as parameters, it would populate the report (as with my one-record report before) but that doesn't seem to be the case.
Refreshing the report viewer also gives me
A data source instance has not been supplied for the data source 'Dataset1'.
I created a dummy dataset in the RDLC file just to be able to use a Tablix as was suggested in several threads I read around. I'd really prefer if I could just use the dataset I made from scratch rather than use the wizard for that.
Private Sub btnGenerateReport_Click(sender As Object, e As EventArgs) Handles btnGenerateReport.Click
Dim query As String
query = BuildQuery()
SQLControl = New SQLControl
Try
If Not query = String.Empty Then
SQLControl.QueryParams(query)
If SQLControl.SQLDS.Tables(0).Rows.Count > 0 Then
FetchData()
End If
End If
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Exclamation, "Report Maker")
End Try
End Sub
Private Sub FetchData()
Dim dataSource As ReportDataSource
Dim PID As Integer
Dim Name As String
Dim ApplicationStatus As String
Dim Address As String
rvPreview.Reset()
rvPreview.LocalReport.ReportPath = "C:\Users\xxx\Documents\Visual Studio 2015\Projects\My Project 1\My Project 1\Reports\myReport.rdlc"
rvPreview.LocalReport.DataSources.Clear()
dataSource = New ReportDataSource()
_rparams = New List(Of ReportParameter)
With SQLControl.SQLDS.Tables(0)
For x As Integer = 0 To .Rows.Count - 1
PID = .Rows(x).Item("PID")
Name = .Rows(x).Item("LName") & ", " & .Rows(x).Item("FName")
ApplicationStatus = .Rows(x).Item("ApplicationStatus")
Address = .Rows(x).Item("StreetAddress") & ", " & .Rows(x).Item("City")
_rparams.Add(New ReportParameter("PID", PID))
_rparams.Add(New ReportParameter("Name", Name))
_rparams.Add(New ReportParameter("ApplicationStatus", ApplicationStatus))
_rparams.Add(New ReportParameter("Address", Address))
For Each param As ReportParameter In _rparams
rvPreview.LocalReport.SetParameters(_rparams)
Next
Next x
rvPreview.RefreshReport()
End With
End Sub
At the begining I have to mention that I use RDLC reports with C#, but the solution should be very similar in vb.net.
I usualy prepare every report as separate project (so I have separate DLL for every report) and use a separate class in this project to handle everything I need to do with report. I add Every RDLC file just under the project (main report file and subreports files). In my case I can read every RDLC file like a stream just using project namespace and RDLC filename as in this sample code below
Assembly assembly = Assembly.GetExecutingAssembly();
Stream stream = assembly.GetManifestResourceStream("[Some project namespace].[Some report filename].rdlc");
Then I use a code like this to connect that stream with report viewer (the stream in this code is the same object as above but this code is in another class which has access to report viewer object)
ReportViewerControl.LocalReport.LoadReportDefinition(new StreamReader(stream));
You can provide a DataSet for your report in very simple way. You can use object of the System.Data.DataTable class for table (I call this object as yourTableObject in code below) and System.Data.DataRow class for rows in that table. When you put all your data in the table then you can provide it to the report using code like this
//I use DataSet1 as dataset name because you use this name in your report definition
ReportDataSource rds = new ReportDataSource("DataSet1", yourTableObject);
ReportViewerControl.LocalReport.DataSources.Add(rds);
Ofcourse provided table should have the same fields like the dataset in your report definition.
You have to provide a valid DataSet to the report. Solution is above in point 2.
Background:
I have an old report in which I am trying to add a table and a field. The report works perfectly fine in my web application. (Crystal reports ver. 11.5.9.1076)
After adding a table I get the error:
System.Runtime.InteropServices.COMException: Failed to open connection
This happens whether I add a table, command, or stored procedure to the report. (Connecting to Oracle database)
Things I've tried:
Add table (crashes), remove table (works again)
Click the "Verify database" button in the Database menu
Set database location and update the newly added table
Previewing the report seems to work
As for how I'm providing the data:
Create and load ReportDocument (VB.net)
Populate DataSet
Call SetDataSource method with DataSet as param
ExportToHttpResponse as PortableDocFormat
Here is what we had to do in order to make this work in our crystal reports: after loading the report, we loop through each of the DataSourceConnections in the report and update the connection information.
For Each oConnection As IConnectionInfo In oReport.DataSourceConnections
If fUseIntegratedSecurity Then
oConnection.SetConnection(sServerName, sDatabaseName, True)
Else
oConnection.IntegratedSecurity = False
oConnection.SetConnection(sServerName, sDatabaseName, sUserLogon, sUserPassword)
End If
Next
The actual connection details are provided elsewhere in our app, so I am just showing placeholders in the code above.
When I ran my crystal report, I run into an error where its shows missing parameter values
Below is my code
_crAdviceRpt.Load("C:\Users\whatever\AD_AdviceTemplate.rpt")
Dim ds As ADDataset = New ADDataset
Dim dt As DataTable = ds.Tables.Add("ADDatatable")
dt.Columns.Add(New DataColumn("strLinesList", Type.GetType("System.String")))
Dim dr As DataRow
dr = dt.NewRow
dr("strLinesList") = strLine
dt.Rows.Add(dr)
_crAdviceRpt.SetDataSource(ds.Tables(1))
CrDiskFileDestinationOptions.DiskFileName = "location.pdf"
CrExportOptions = _crAdviceRpt.ExportOptions
With CrExportOptions
.ExportDestinationType = ExportDestinationType.DiskFile
.ExportFormatType = ExportFormatType.PortableDocFormat
.DestinationOptions = CrDiskFileDestinationOptions
.FormatOptions = CrFormatTypeOptions
End With
_crAdviceRpt.Export()
If Not _crAdviceRpt Is Nothing Then
_crAdviceRpt.Close()
_crAdviceRpt.Dispose()
_crAdviceRpt = Nothing
End If
In my dataset, it does like this:
ADDDataset.xsd-> ADDatatable -> strLinesList
strLinesList is my column over here
In crystal report designer, I drag the strLinesList over to my .rpt
I'm not sure what is wrong but I'm pretty sure that something is missing in my code, so anyhere is appreciated
The Solution for this is to reorder the Crystal Parameters to match the Query Prompts
1) Open the problem report in Crystal Designer
2) Right click the Parameters section and select reorder parameters
3) Set the Parameter order to match that of the Prompts in the query
4) save the report and retest
The Verify Database command on the Database menu checks the alias pointers stored in a report file to verify that the database files expected are located in the indicated directories. If the databases are not found in the specified location, the program notifies you of the discrepancies.
Using the Verify Database process
When you choose Verify Database from the Database menu, the program checks the active databases and reports. If it detects changes, the report must be adapted to prevent errors. The program displays the Map Fields dialog box when it detects either of these types of changes to the database:
- The name of a database field that is used in the report has changed
- The database has been upsized from a PC data source to an SQL data source.
Crystal Reports automatically adapts the report (and does not display the Map Fields dialog box) if it detects any of these changes:
- Fields have been added to the database
- Fields that are not used in the report have been deleted from the database
- Field positions have changed in the database
- Data types have changed for fields in the database.
Using the Verify on Every Print process
Verify on Every Print triggers the Verify Database command every time you print your report.
- If there is a check mark beside Verify on Every Print, the option is active. It triggers Verify Database every time you print.
- If there is no check mark beside it, the option is inactive. The option is inactive by default.
Link
WP8, VS12, & C#
I've started creating an app which allows me to store relational data in a local database using LINQ to SQL.
What I'd like to do next is be able to update the existing data...I would click an icon in the appbar and be taken to the previously saved data so I could update it.
I've looked on msdn... Local database for Windows Phone, and I would like to know if the following code I see at section Using the database > Updating data is valid given my LINQ to SQL set-up. If so, how do I go about adding this code to allow updating?
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
//Call base method
base.OnNavigatedFrom(e);
//Save changes to the database
toDoDB.SubmitChanges();
}
If anyone could point to a working example or help me hook up the ability to update data, I would be grateful.
Much Thanks,
k
Yhello, dunno if you still working on your project but I've got a solution for you.
From your site (msdn), here what I found :
First, query the database for the object that is to be updated. Then, modify the object as desired. Finally, call the SubmitChanges method to save the changes to the local database.
So, you need to query your db (example from my own VB.net code)
Dim monContact = From contact As Authentification In bddGLI.TableAuth Select contact
Execute the query and get the result in a collection
Dim resultCollection = New ObservableCollection(Of Authentification)(monContact)
Run through this collection with a ForEach loop and modify your object
For Each elem As Authentification In resultCollection
elem.Mail = txtEmail.Text
elem.Nom = txtNom.Text
elem.Prenom = txtPrenom.Text
Next
And don't forget to save your db
bddGLI.SubmitChanges()
Now, how to check if you really updated your data ?
Where I create my db, i inserted some data test in my table
Using db As New GeoLiveInfoDataContext(GeoLiveInfoDataContext.DBConnectionString)
If db.DatabaseExists() = False Then
db.CreateDatabase()
Dim contact As New Authentification
With contact
.Nom = ""
.Prenom = ""
.Mail = ""
End With
db.TableAuth.InsertOnSubmit(contact)
db.SubmitChanges()
End If
End Using
http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh286408(v=vs.105).aspx
Go to C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v8.0\Tools\IsolatedStorageExplorerTool
SHIFT + right clic => open prompt here
ISETool.exe ts xd {ID APP HERE FROM MANIFEST } {PATH}
Don't forget to install your app on the emulator or device (not debugging)
Now at your path, you have a .sdf which can be open with SQL server Compact Edition.
Do this command before and after updating and check the difference.
Use Sqlight -- Here is a great example http://code.msdn.microsoft.com/wpapps/Using-Sqlite-with-WP8-52c3c671
The important thing in updating the data in the database is, that you handle with the same object which results the query from database and don't copy it. You can pass the object from the query results to other objects or functions but make sure that it is still the same object on the heap. Just in this case the SubmitChanges works. I did it the first time wrong and copied it for the page object and then passed it back and the SubmitChanges didn't work.
Using VB.NET in an SSIS package, how do I populate an SQL Server table with the users in multiple Active Directory domains (in the same forest)?
I went the route of using a query similar to Siva's approach except instead of a linked server query, I use the ADSI provider. Active Directory SSIS Data Source
SELECT
distinguishedName
, mail
, samaccountname
, Name
, employeeNumber
, objectSid
, userAccountControl
, givenName
, middleName
, sn
FROM
'LDAP://DC=domain,DC=net'
WHERE
sAMAccountType = 805306368
ORDER BY
sAMAccountName ASC
The code in the referenced post will pull all users from a given domain. After converting from NTEXT to TEXT to String, I then use the distinguished name and the DirectoryServices assembly to enumerate all the first order groups for a user via their distinguished name. It does not address nested groups. Conveniently enough, that post covered a 2005 SSIS implementation so the logic is in VB.
Script Component (VB.NET) with System.DirectoryServices
Here is a sample logic that import Active Directory users information from one domain into database table with the help of VB.NET in Script Component configured as Source. This sample was tested in SSIS 2012 but should work in SSIS 2008 and above. This logic will not work in SSIS 2005 because the namespace System.DirectoryServices.AccountManagement was introduced only in .NET framework 3.5 and SSIS 2005 uses .NET Framework 2.0
Create an SSIS package. This sample uses SSIS 2012.
Create an OLEDB Connection Manager that would connect to the SQL Server database. If you created a data source, add the data source to the package's connection manager tab.
Drag and drop a Data Flow Task onto the Control Flow tab.
Double-click the Data Flow Task to switch to the Data Flow tab.
Drag and drop a Script Component onto the Data Flow tab.
Check Source on the Select Script Component Type dialog and click OK.
Double-click the Script Component to open the Script Transformation Editor. Click Inputs and Outputs tab page.
Rename the Output to ActiveDirectory to give a meaningful name.
Select Output Columns and click Add Column to add each of the below mentioned columns. This is only to illustrate this example. You might need to add columns of your preference.
Column definition within script component
Name Data Type Length
----------------- ------------------------ ------
FirstName Unicode string [DT_WSTR] 255
LastName Unicode string [DT_WSTR] 255
SAMAccountName Unicode string [DT_WSTR] 255
UserPrincipalName Unicode string [DT_WSTR] 255
After defining the columns, click Script tab page
Change the ScriptLanguage to Microsoft Visual Basic 2010
On the Solution Explorer, right-click the Script Component project and click Add Reference.... Add references to the following namespaces.
Namespaces to be referenced in the script component
System.DirectoryServices
System.DirectoryServices.AccountManagement
Paste the below VB.NET code into the Script component. Replace the section <Your domain name goes here> with your appropriate domain name. The code initializes PrincipalContext and PrincipalSearcher objects in PreExecute method and then disposes them in PostExecute method. CreateNewOutputRows method loops through each of the row found in AD to fetch the user attributes information.
Script component code (VB.NET)
#Region "Imports"
Imports System
Imports System.Data
Imports System.Math
Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper
Imports Microsoft.SqlServer.Dts.Runtime.Wrapper
Imports System.DirectoryServices.AccountManagement
Imports System.DirectoryServices
#End Region
<Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute()> _
<CLSCompliant(False)> _
Public Class ScriptMain
Inherits UserComponent
Dim principalContext As PrincipalContext = Nothing
Dim principalSearcher As PrincipalSearcher = Nothing
Public Overrides Sub PreExecute()
principalContext = New PrincipalContext(ContextType.Domain, "<Your domain name goes here>")
principalSearcher = New PrincipalSearcher(New UserPrincipal(principalContext))
MyBase.PreExecute()
End Sub
Public Overrides Sub PostExecute()
principalContext = Nothing
principalSearcher = Nothing
MyBase.PostExecute()
End Sub
Public Overrides Sub CreateNewOutputRows()
For Each principal As Principal In principalSearcher.FindAll()
Dim entry As DirectoryEntry = TryCast(principal.GetUnderlyingObject(), DirectoryEntry)
With ActiveDirectoryBuffer
.AddRow()
If entry.Properties("givenName").Value IsNot Nothing Then
.FirstName = entry.Properties("givenName").Value.ToString()
Else
.FirstName = "Unknown"
End If
If entry.Properties("sn").Value IsNot Nothing Then
.LastName = entry.Properties("sn").Value.ToString()
Else
.LastName = "Unknown"
End If
If entry.Properties("samAccountName").Value IsNot Nothing Then
.SAMAccountName = entry.Properties("samAccountName").Value.ToString()
Else
.SAMAccountName = "Unknown"
End If
If entry.Properties("userPrincipalName").Value IsNot Nothing Then
.UserPrincipalName = entry.Properties("userPrincipalName").Value.ToString()
Else
.UserPrincipalName = "Unknown"
End If
End With
Next
End Sub
End Class
Close the Script Transformation Editor.
Drag and drop an OLE DB Destination onto the Data Flow tab. Connect the Script component to the OLE DB destination to redirect the source output. Select the appropriate OLE DB Connection Manager and the table where the data should be inserted into.
Ways to improve this approach:
This sample provides loading information from only one domain. If you have multiple domains, you could stored them in a table. Fetch information of all the domain lists and use Foreach Loop Container available on the Control Flow to loop through each domain and get the users information using the above mentioned approach. May be there is also a better way to do this within VB.NET.
Active Directory User Attributes
You can find the complete list of Active Directory user attributes in the below MSDN link. You need to click the links to find the LDAP-Display-Name.
All Attributes (Windows)
Here is another link that might help to get the user object attributes
User Object Attributes (Windows)
Linked Server approach:
Set up a linked server to connect to Active Directory:
Here is one possible option using Linked Server on SQL Server that does not actually require VB.NET, if that is an option for you. The queries given below are only for syntax references. Please read the links for proper usage of these SQL Server objects.
You could set up a linked server on SQL Server to connect to the Active Directory using OLE DB Provider for Microsoft Directory Services. Below is a sample script that would set up a linked server and map it with a login that has access to the Active directory.
Usage of sp_addlinkedserver (Transact-SQL)
Usage of sp_addlinkedsrvlogin (Transact-SQL)
Sample script to set up linked server:
USE [master];
GO
EXEC master.dbo.sp_addlinkedserver
#server = N'ADSI'
, #srvproduct = N'ADSI'
, #provider = N'ADsDSOObject'
, #datasrc = N'adsdatasource'
, #provstr = N'ADSDSOObject';
GO
EXEC master.dbo.sp_addlinkedsrvlogin
#rmtsrvname = N'ADSI'
, #useself = N'False'
, #locallogin = NULL
, #rmtuser = N'<User account goes here...>'
, #rmtpassword = '<Password goes here...>';
GO
Use OpenQuery to query Active Directory:
You can then use OpenQuery to query the Active Directory for user information. Read the below link on MSDN for more information on how to formulate the query.
Search Active Directory - Distributed Query
Sample script to query Active Directory:
SELECT *
FROM OPENQUERY
( ADSI
, ' SELECT *
FROM ''LDAP://<OU path goes here...>''
WHERE objectClass = ''user'''
);
How to use this data in SSIS package:
You could set up this query as an SQL Server view and then call the view from OLE DB Source available on Data Flow Task within SSIS package and then redirect the output to an OLE DB Destination to populate the database tables.