Quantcast
Channel: SCN : Discussion List - SAP Crystal Reports, version for Visual Studio
Viewing all articles
Browse latest Browse all 3636

CR9 --> CR13 upgrade (with PESetSQLQuery() )

$
0
0

Hello,

 

As a preamble, this is my first time posting on SCN, plus I'm a bit of a grasshopper at Crystal -- and the Rules of Engagement link was broken for me -- so apologies if I’m doing it wrong or asking a dumb question.

 

The product I’m working on includes a reporting framework that was originally built around Crystal Reports 9 (or earlier?).  The full details of what we're trying to do are a bit lengthy, so let me ask the "Executive Summary" version of the question, followed by the details for those who enjoy a hefty read.

 

 

Executive Summary:

 

We're hoping to upgrade the application to use CR13/14.  The report framework relies on the existence of PESetSQLQuery() to add a Where clause to the reports’ queries, but PESetSQLQuery() (or an equivalent) doesn't seem to exist in CR13.  Changing the reports is not an option, and we want to change existing code as little as possible.  Is it possible to perform such an upgrade without changing the reports?

 

 

Long Details:

 

The product we have is essentially a two-tier, database-driven desktop application.  The product ships with some reports, but additionally allows the user to create their own reports based on virtually the complete DB schema (i.e. we don't limit external report writers to a narrower interface).  The reports sit on the end-users' PCs.  The product doesn't distinguish between inhouse reports and customer-created reports. 

 

The reports rely on PESetSQLQuery() to achieve both generic filtering and row-level security:

 

On the generic filtering side, all reports are requested from the application through a shared, static UI: this UI allows the user to filter on various columns from various tables, but knows nothing of the report being generated.  To use an approximate example, suppose the product is from sports stats, where one of the filterable columns exposed by the reporting UI is BattingAverage (in the BaseballPlayerStats table), and one of the reports is "Hockey Goaltender Names".  When a user comes to generate a report, they may choose a "Hockey Goaltender Names" report, and select "For players whose Batting Average is greater than .300".  The reporting framework asks for the Crystal Report's query and looks for the BasebasePlayerStats table in the report's FROM clause.  If the framework finds the table, it appends a suitable WHERE clause to the query (which was possible in CR9, using PESetSQLQuery() ); if it doesn't find the table, it simply ignores the user's input.  In the "Hockey Goaltenders with a batting average greater than .300" example, the batting average part would simply get ignored, since the "Goaltenders" report doesn't refer to BaseballPlayerStats.  To sum up in other words, report construction is the responsibility of the report's author, but the application assumes responsibility for filtering the results.

 

In addition to this, the application also takes on the responsibility of silently (from the end-user's perspective) handling row-level security.  Continuing with the (approximate, if increasingly tortured) example, the application can be configured (dynamically) to support "Rookie Analyst" users that can only see players younger than 25 years old and "Veteran Analyist" users that can only see players older than 25 years old.  If Jane Youngsmith, the Rookie Analyst, logs in and ask for a "Hockey Goaltender Stats Summary" Report, it'll only show her the players that she has permission to see (i.e. those less than 25 years old), regardless of the filtering option she chooses through the UI.  This is achieved by an additional WHERE-clause appended into the report's SQL query -- again, which was possible using PESetSQLQuery().  This has been done strictly application-side and transparently to the user and the report authors, in order to enforce those permissions.  (In other words, since anyone could write their own report with its own query, this is done in an attempt to prevent Jane Youngsmith from writing her own report that allows her to see players older than 25.)

 

I should pause for a moment to say that I'm not arguing for or against the architecture of such a system.  This is simply what exists, and because it's rather complicated, and because it works, and because regression testing all our reports is a very, very daunting task, and because of a variety of reasons, people are Very Reluctant to change it.

 

I said, "Because it works" in the last paragraph, but that's the rub.  It worked for CR9.0 thanks to the PE[Get/Set]SQLQuery() functions, but we're trying to upgrade to CR13/14.  Whereas PEGetSQLQuery() has merely been migrated in CR13 (to ISCDReportClientDocument.RowsetController.GetSQLStatement() ), it seems that PESetSQLQuery() has been disappeared altogether.

 

We've been investigating how to change the calls to Crystal to be CR13-friendly, while trying to change as little else as possible, but we're starting to reach the point that this looks impossible.  However, no one on the team has sufficient Crystal experience to make that call categorically -- but simultaneously, no one can identify anything that /will/ work.  Here are some things that we've tried:

 

 

Try 1:  Run the (modified) query programmatically to produce a one-table RecordSet, and use ReportDocument.SetDataSource() to essentially say, "Thanks Report, we used your Query as a basis to generate the record set for you -- now don't worry about your Query anymore: just use these results."

 

Advantage: This would be the least-intruisive approach for us.

 

Problem 1:  This doesn't seem to be possible.  (Or at least, that doesn't seem to be what SetDataSource() is for, and we haven't found an API that allows for this.)

 

 

Try 2:  Use ReportDocument.SetDataSource() with an in-memory DataSet, where the tables in the DataSet have been "pre-filtered" by pushing the Where clauses into the query statements used to create the tables.  In other words, this effectively converts:

 

SELECT A.x, B.y

FROM A, B

WHERE A.x = x1 AND B.y = y1

 

into

 

SELECT A.x, B.y

FROM

(SELECT A.x

FROM A

WHERE A.x = x1) as A,

(SELECT B.y

FROM B

WHERE B.y = y1) as B

 

Advantage:  Although it's more intruisive than Try 1, it at least doesn't require us to change the Reports.

 

Problem 2A: It's not clear to me that those two forms are equivalent in general (though I'm having trouble proving or disproving it).  Moreover, although exploratory tests produce intermediate results that look identical, the end-product reports are sometimes different (though sometimes the same).  I'm not sure if this is a fundamental problem, or if it's only a superficial coding mistake that I haven't spotted yet. 

 

Problem 2B: Regardless of its correctness, it feels like a hackish way of doing it.

 

 

Try 3:  Use CrystalReportViewer.SelectionFormula, with a "CR13-friendly where-clause"  --  which seems to be the correct way of doing it in CR13(?)

 

Advantage: In theory, this could be nearly as non-intruisive as Try 1.

 

Problem 3A: The SelectionFormula property, which takes clauses approximately of the form "{table.column} = value", seems to require that table.column exist in the report's SELECT clause.  This is a problem for us, since that's generally not the case in our reports.  E.g. suppose the report's query is:

 

SELECT A.name

FROM A

 

but the SelectionFormula is "{A.battingAverage} > .300".  To make this work, it seems that we'd need to modify the report such that its query would be:

 

SELECT A.name, A.battingAverage

FROM A

 

but modifying the report is forbidden.

 

Problem 3B: SelectionFormula seems to only accept "primitive" filters; "nested" filters of the form "{a.id} in (SELECT B.id FROM B where B.age > 25)" seem forbidden.  I haven't been able to figure out if that's a fundamental (if understandable) limitation, or if I merely haven't got the syntax yet.  We admittedly haven't yet tried to run these subqueries separately and then stick the results into the SelectionFormula, partly because that's already starting to cross the the "change as little of the framework as possible" line, and partly because Problem 3A may be a showstopper for this route anyway.

 

Having said all that, the question boils down to, "Is it simply impossible to do a CR9 --> CR13/14 upgrade given these constraints?"  (As a corollary, I suppose the next question would be, "If it is indeed impossible, is there an obvious next-best upgrade path?"  And of course, "If it's not impossible, what is the right way of doing it?")  There are some other things that I've seen, but I don't have a good understanding of them.  For example, I recently discovered references to Command Objects and Universes, but I'm having trouble understanding whether they apply in this case.  More broadly, I think I've reached the point that, "A lot of things initially look promising, but ultimately seem to dead-end.  I could do a self-guided random walk in CrystalLand for years; maybe it's time to ask people who actually know what they're talking about about whether this is possible."

 

Sorry for the long-windedness, but thanks greatly!

 

Kevin


Viewing all articles
Browse latest Browse all 3636

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>