Navigation

Search

Categories

On this page

Using Parameters in the Reports Module
Reports Module v5.0 Released to Tracker
More Better Familiarize Yourself with a Toolkit? (Name in progress) - #1
Applying the Single Responsibility Principle at a Product level
OneQuery - A Fluent Interface to Database Queries
Test Post from Windows Live Writer
New Blog

Archive

Blogroll

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 16
This Year: 7
This Month: 0
This Week: 0
Comments: 1

Sign In
Pick a theme:

 Wednesday, December 19, 2007
Wednesday, December 19, 2007 2:17:04 PM (GMT Standard Time, UTC+00:00) ( DNN | Reports Module )

A common question that comes up in the Reports Module forums is "How can I display data relevant to the current User in the Reports Module?". So, I figured I should write a blog post about a feature that has been in the Reports Module for a few versions. When writing your SQL Scripts for the Reports Module, you automatically have access to four parameters: @PortalID, @TabID, @ModuleID and @UserID. When the SQL Script is executed, these are replaced by the ID of the current Portal, Tab, Module and User (respectively).

So, if you wanted to display a list of Roles for the currently logged in user you could use this script:

SELECT  R.*

FROM    {oQ}UserRoles UR

    INNER JOIN dnn_Roles R

    ON         UR.RoleID = R.RoleID

WHERE   UR.UserID = @UserID

When you run this script, the current user's ID will be substituted in the place of the @UserID parameter. (Note: This is done by SQL Server itself, which avoids SQL Injection attacks). Also, the {oQ} token is replaced with the Object Qualifier configured for your database (if you configured one in your web.config file)

Here's another example. It's a script that retrieves the Website profile property for each user in the current portal.

SELECT     U.Username,

          (SELECT     PropertyValue

           FROM       {oQ}UserProfile AS UP

           INNER JOIN {oQ}ProfilePropertyDefinition AS PPD

           ON         PPD.PropertyDefinitionID = UP.PropertyDefinitionID

           WHERE      UP.UserId = U.UserId

           AND        PropertyName = 'Website'

           AND        PropertyCategory = 'Contact Info') AS 'Website'

FROM       {oQ}UserPortals AS UP

INNER JOIN {oQ}Users AS U

ON         UP.UserId = U.UserId

WHERE      PortalID = @PortalID

The italicized section is the part that actually retrieves the property value, you can replace the PropertyName and PropertyCategory values as you like and repeat this section multiple times to bring back multiple profile properties.

One of the planned future features for the module is to support user-specified parameters. This means you could place a text box, drop down, calendar or other control on the view page for the module and the value of this control would be used as a parameter to the Report. At the moment you're limited to these four parameters, but there's still a lot you can do with them!

Comments [0] | | # 
Wednesday, December 19, 2007 1:42:02 PM (GMT Standard Time, UTC+00:00) ( DNN | Reports Module )

After a few delays, version 5.0 of the Reports Module has been released to the Module Release Process. This means that it should be released shortly (though given the time of year, it may take a couple of weeks). I'll be posting some How-To screencasts walking through the new features (and some old ones too) in the next week or so. I'm also working on a full User's Guide to be released shortly.

One important note regarding Reports 5.0: The module requires at least v4.6 of the DotNetNuke core, it will NOT run on a previous version of the core. This is because of the new Visualizer and Data Source installers which use the Package Installer introduced in v4.6. I hope to release a version of the module with the installer portions removed which will be referred to as "Version 4.9".

To give you an idea of what's coming, here's an excerpt from the release notes containing a list of resolved issues in this version (The same list can be found here: http://support.dotnetnuke.com/project/RoadMap.aspx?PROJID=36)

  • RPT-5634 JavaScipt error when first configuring Reports DNN _04.05.01
        A JavaScript error was occuring on the main settings page, this has been corrected
  • RPT-5676 HTML Decoding in XSL Visualizer
        Fix through RPT-6514
  • RPT-4698 Clean up interface for Reporting Services Visualizer
        Interface for Reporting Services Visualizer has been improved significantly the Visualizer has also been renamed to the "Microsoft ReportViewer Visualizer"
  • RPT-5715 Include {databaseOwner} token in upgrade SQL scripts
        Scripts have been corrected
  • RPT-5791 Run Reports on Demand
        Reports can now be run "on-demand" rather than automatically on load
  • RPT-5806 Support the EnableExternalImages property of ReportViewer control
        The EnableExternalImages and EnableHyperlink properties are now supported, along with many others (see RPT-4698)
  • RPT-3994 Alternate Data Sources
        Data Sources Framework allows Reports to run queries against other Databases (SQL Server, Access, Oracle, etc.)
  • RPT-6466 Disable the Use of Parameters while Caching is enabled
        Paramaters are disabled when Caching is enabled due to a serious privacy risk
  • RPT-6514 HTML Decoding and Encoding of fields retrieved from database
        Fields can now be individually HTML Encoded and HTML Decoded before being passed to the Visualizer
  • RPT-6516 Report Info Pane
        An info pane displaying the title and description of the report can now be displayed on the main screen
  • RPT-6454 Allow Users to specify custom CSS Styles and Classes for the Grid in the Grid Visualizer
        Users can use custom CSS to style the Grid Visualizer
  • RPT-6438 Add a setting to enable/disable Grid Lines in Grid Visualizer
        Grid Lines can now be configured in the Grid Visualizer

Keep an eye on the blogs for more updates, I'll make sure to post here when the module is released!

Technorati Tags: ,,
Comments [0] | | # 
 Saturday, December 15, 2007
Saturday, December 15, 2007 9:04:40 AM (GMT Standard Time, UTC+00:00) ( )

While attempting to avoid infringing on the name from a segment from a popular internet audio talk show, I had an idea for a "quick tip" when I was reading a recent .Net Tip of the Day.

Throughout the product development cycle, occasionally certain methods become obsolete. If you can't modify those methods, will need to write another implementation of the method using a slightly different name or signature. To maintain compatibility, you do not want to remove the old method and break your code. This is where the .NET Obsolete attribute comes in handy:

[Obsolete("Use the new LogRequestEx instead.")]
public static void LogRequest(string feedUrl, string referer)
{
    ...

Setting the Obsolete attribute as above makes a warning message appear in the Visual Studio's Error List stating that the particular call to a method is obsolete. The warning message also includes your personalized message that you pass as the attribute's argument (such as, "Use the new LogRequestEx instead").

So, I figured I'd start of this semi-frequently series of .Net tips with an extension to this one :). Not only can you have Visual Studio display a warning, but if you really don't want people using the method you can configure it to display an error message if the user tries to use the method. For example, in the example above you need only add a boolean value for the second constructor parameter "error":

[Obsolete("You must use the new LogRequestEx instead.", true)]
public static void LogRequest(string feedUrl, string referer)
{
}

More details can be found on MSDN

Comments [0] | | # 
 Thursday, December 13, 2007
Thursday, December 13, 2007 2:57:36 AM (GMT Standard Time, UTC+00:00) ( )

One of the big concepts in Object Oriented Programming, is the Single Responsibility Principle (SRP), which essentially states that every object in a computer program should have a single responsibility. I recently started thinking about where OneQuery fits in to the whole ORM landscape. OneQuery is designed for a very singular purpose. It is a Database-agnostic Query engine. That alone is its responsibility and I think it should stay that way. So, in fact, OneQuery doesn't fit into the ORM landscape, because it isn't an ORM. OneQuery is directly focused on the problem of writing queries against any database and receiving tabular results (i.e. IDataReader).

Does this mean that you should ignore it if you are looking for an ORM? No, I don't believe so. Just because OneQuery isn't an ORM, doesn't mean it can't work with ORM tools. One of the ideas sitting at the back of my head is to create an ORM called "OneMapper" which would sit on top of OneQuery and add ORM features. The fundamental difference between the combination of OneMapper and OneQuery and other ORM tools is that you could use OneQuery without OneMapper. Tools like SubSonic and NHibernate have a tight coupling between their ORM components and their database query components. The point is, I see OneQuery as being an example of SoC/SRP being applied at a "Product" level, rather than at a Class level. I want OneQuery to be a really good query engine, not a pretty good ORM and I think that separating those concerns makes that much more possible.

The main problem I was thinking about when I dreamt up OneQuery is how DotNetNuke could achieve true Database-agnosticism in its Data Access Layer. One option would be to use a tool like NHibernate or SubSonic to completely rewrite the Data and Business Layers with a true ORM. However the problem there is that it would be a wholesale change and would probably introduce some major breaking changes.

Another option would be to use something like SubSonic's Query Tool (which actually inspired me to develop OneQuery), which allows you to build database-agnostic queries and execute them, receiving tabular data in return (rather than objects). Then, the existing DotNetNuke infrastructure could handle the ORM stuff. This would basically mean replacing the existing "SqlDataProvider" with a "SubSonicDataProvider" and basically avoiding any breaking changes by just scooping out the old SQL Server-specific guts and injecting a tasty cream...oops, I mean Database-Agnostic...filling.

So, why not do that? Well, I realized that SubSonic is, first and foremost, an ORM and it will always be focused on that. The Query Tool is a great feature, but it feels like it's just tacked on to the main ORM component. This has two ramifications: First, the ORM will be the primary focus of development and new features in the Query Tool will be fewer and far between. And second, if you just want the Query Tool, you have to bring along the entire ORM system as well (unless SubSonic does some refactoring). At 644KB, SubSonic isn't huge but it isn't tiny either (though, I don't have exact numbers on what portion of that is the ORM and what portion is the Query Tool).

So, that leads me into the primary difference between OneQuery and other tools like NHibernate and SubSonic: OneQuery is not actually an ORM! Its a query engine, and hopefully it will be a darn good one too. That is its primary responsibility and any other cool features (like ORM components or LINQ support) are totally separate concerns.

Now, having said all that, this is just what I've been thinking about recently. Maybe it's all crazy talk. Feel free to sound off in the comments and tell me that :).

Comments [0] | | # 
 Tuesday, December 11, 2007
Tuesday, December 11, 2007 2:21:19 PM (GMT Standard Time, UTC+00:00) ( OneQuery )

Aside from my school work and my work on the DotNetNuke Reports Module (very very close to release now), I've been tinkering with another project over the past few months. It's called OneQuery and its yet another Data Access Layer tool. OneQuery is designed to provide a "fluent interface" to database queries.

What is a fluent interface? Wikipedia defines it as "an object oriented construct that defines a behaviour capable of relaying the instruction context of a subsequent call". Essentially, it means that instead of writing code like this:

List<int> ints = new List<int>();
ints.Add(1);
ints.Add(2);
ints.Add(3);

You can write code like this

List<int> ints = new List<int>().Add(1).Add(2).Add(3);

That's quite a savings and, in my opinion, it's much more readable.

So, what's the point?

Well, recently I've been thinking about the issue of database agnostic...ness (database agnostivity? database agnosticism?). I really want to be able to write data access code that will run on multiple database engines without having to manually translate it. DotNetNuke provides a, theoretically, database agnostic interface through Data Providers. However, to support another database engine, the core DataProvider must be translated, Stored Procedures must be converted and all sorts of "Porting" issues arise. Wouldn't it be nice if you could WORA (Write Once, Run Anywhere... a Java term) your SQL Scripts?

Wait, hasn't this been done?

Of course it has, and many many times. First, there's the elephant in the room, LINQ. However, aside from requiring .Net 3.5, if you want to write database agnostic code, you need to use something like the ADO.Net Entity Framework. OneQuery is designed to work in .Net 2.0, and I'm planning to write a LINQ layer on top of it so that you can write LINQ queries and run them on multiple database engines (not just SQL Server). I think OneQuery could serve as a "migration path" where you can write OneQuery syntax and then move to LINQ syntax when you're ready to move to .Net 3.5 while still keeping the database-agnostic OneQuery core.

There are a lot more database libraries out there as well. SubSonic provides an excellent Object/Relational Mapper (ORM) that allows you to work directly with objects, but sometimes you want a little more control. There are, of course, many others such as NHibernate, IBATIS.Net, and EntitySpaces. However, I found that while working with these tools I would find little things that would annoy me. For example, SubSonic does provide a way for you to directly query the database and get an IDataReader back, but it has an interface I found a little awkward (though it is a nice fluent interface). There are also smaller annoying features such as a lack of support for certain SQL statements (like "INSERT") and a lack of JOIN support. On the other side, tools like NHibernate are really designed to allow you to ignore the database completely, which is a nice feature, but sometimes I need that direct database control.

So, what is OneQuery?

[Wow, I started two sub-headings off with 'so', perhaps that summer at Microsoft is affecting my patterns of speech. They say Microsofties tend to start there sentences with "so" and say "drinking from a firehose" and "super" a lot]

OneQuery is designed to let you focus on writing one query, and allows you to run the query on multiple database systems. Instead of using strings, which the compiler ignores, I wanted to provide a fluent interface and use operator overloading to make the queries as readable as possible.

Enough already, get to the code!

Ok, so here's a sample query using OneQuery's fluent syntax:

query

(I posted it as a screenshot to make sure the spacing worked out, I'll post the text at the end if you want to copy it).

There are a few things I want to do to let you clear that up even further. For example, it would be much easier if you could write ".OrderBy(Product.ListPrice).Desc()", or ".Where(Product.ListPrice.Between(10).And(100))"

Behind the scenes, the only other code you need to "write" is a helper class for the products table. I used quotes there because I'm planning on creating a code generator to do that for you.

CAN HAZ CODE?

Hopefully I've tantalized you a little bit and you'd like to check it out. You can download a preview release from our CodePlex Project Site, and discuss future features there as well. I'm planning a whole bunch of new features including (but definitely NOT limited to):

  • Support for ALL SQL DML Statements (INSERT, UPDATE, DELETE)
  • Full support for SELECT (including JOIN, GROUP BY, HAVING, and sub-queries)
  • A Code Generator to create the helper classes
  • and more!

Please let me know what you think! I want to make sure this system solves problems for as many people as possible, and the best way to do that is to get contributions from the community as early as possible. The CodePlex site has plenty of places to contribute, so please check it out!

Sample Code in Text Form
IDataReader rdr = Product.Query()
                         .Where(Product.ListPrice > 10 & Product.ListPrice < 100)
                         .OrderBy(Product.ListPrice, SortDirection.Descending)
                         .ExecuteReader();

Comments [0] | | # 
 Tuesday, November 20, 2007
Tuesday, November 20, 2007 2:41:33 PM (GMT Standard Time, UTC+00:00) ( Cool Software | Random Stuff )

Just writing a test post from Windows Live Writer. Look for a future, more detailed post about it!

Technorati Tags:

Here's a map!

Map image

ooo...fancy...

Comments [0] | | # 
 Thursday, November 15, 2007
Thursday, November 15, 2007 7:37:56 PM (GMT Standard Time, UTC+00:00) ( )
So, this is my first post in my new blog. Just a test post for now, but hopefully I'll put more interesting things here :)

Comments [0] | | # 

Search with Google

Google