- Delete all code files associated with report files (in this case, delete Inventory*.cs)
- In Visual Studio, R-click each report file and select the "Run Custom Tool" context menu item
- Rebuild your solution
Monday, June 21, 2004
Crystal Reports' -- Auto-gen'd code files
Wednesday, June 16, 2004
Setting Crystal Report's Database Info at Run-Time
- Modifying even just a few reports with this mechanism is time consuming
- Changing a report's data source, although infrequent, is not a one-time event
- Each developer has different test databases to run the reports against
- Moving the ASP.NET app through Development, Testing, and Production phases requires using different data stores for the reports
SqlConnection conn = EnterpriseDataStore.GetConnection(<DataStore Name>);
CrystalDecisions.Shared.ConnectionInfo connInfo = new ConnectionInfo();
connInfo.DatabaseName = conn.Database;
connInfo.ServerName = conn.DataSource;
// Leave UserID & Password alone if report was designed for Trusted Security (NT Integrated)
connInfo.UserID = <user name>;
connInfo.Password = <user password>;
foreach(CrystalDecisions.CrystalReports.Engine.Table tbl in rpt.Database.Tables) {
CrystalDecisions.Shared.TableLogOnInfo logOnInfo = tbl.LogOnInfo;
logOnInfo.ConnectionInfo = connInfo;
tbl.ApplyLogOnInfo(logOnInfo);
}
The combination is powerful. Now I can change the connection string info as part of the app config and have the reports point to the right data store dynamically. Each developer and app environment (Test, Production) has the config setting in machine.config or web.config, so the code can move seamlessly among all environments.
Saturday, June 12, 2004
Crystal Reports: Navigation in ASP.NET
To resolve this problem, I only had to make slight modifications: detect the navigation event & skip a bit of code during navigation.
On the page's PreRender event:
- Load the Report Document (.rpt)
- If not navigating (use CRV's Navigate event & set flag>...
- Set the date range info on the Report Doc
- Set CRV.ReportSource to the Report Doc
- And, of course, call base.OnPreRender to give CRV it's opportunity to do prerender processing
The primary issue of the viewer always rendering page 1 was caused by setting the date info again.
Tuesday, June 01, 2004
Stored Procedures for DAAB's SqlHelper.UpdateDataset
- You can't add a row to the DataTable with a null value for the identity column (since you should have set the DataTable's PrimaryKey to the identity column)
- Using a flag value (e.g., -1) for the new row's identity column works fine until you try to add more than one row. (An exception occurs announcing a primary key violation due to the 2nd new row's identity column being -1)
- Trying to manually update the persisted new row's identity column in the DataSet, although a good first guess, is not a good way to go
The big trick for inserts is to structure the stored procedure (sproc) to update the data, and then return the entire row for the updated item. (Just returning the new identity value doesn't suffice). Consider a simple table: Phonelist (EntryId, Name, PhoneNumber). This table contains three columns:
- EntryId -- an auto-generated identity column for uniqueness.
- Name -- a person's name
- PhoneNumber -- the person's phone number
An appropriate sproc for adding new rows to this table would look like this:
create stored procedure Phonelist
(@name varchar(50), @phoneNumber varchar(15))
as
insert into Phonelist (Name, PhoneNumber)
values (@name, @phoneNumber)
select EntryId, Name, PhoneNumber
from Phonelist
where EntryId = @@IDENTITY
return
Notice that each of the columns used to originally populate the DataTable in the DataSet are selected and returned filled with the data just inserted (including the auto-generated identity column). Once you set up the correct SqlCommands for each of the three types of operations (insert, delete, update), then just call SQLHelper.UpdateDataset. The underlying DataSet will auto-magically populate the identity column for the new row based on the row returned from the sproc. Very nice!
One last point: Don't forget to grant Execute permission to the appropriate user account (i.e.,