Statement lambdas cannot be converted to expression trees in Workflow Foundation 4.0 - vb.net

I've been pulling my hair out on this for awhile. I have a custom activity that accepts an InArgument like such:
[RequiredArgument]
public InArgument<Func<IDataReader, T>> Projection { get; set; }
And later on I use this Projection in a Select statement on a data reader after an SQL query like so:
results = reader.Select<T>(context.GetValue(this.Projection)).ToList();
Now, the only difficult part is actually passing the func variable in the VB expression. Specifically in this case, T is a list of RawTie objects. But every time I try to do something complicated with the expression to assemble a list from the reader, I get the error: Statement Lambda Functions are not supported in this context.
Here is an example of an expression I attempted. Keeping in mind VB is not my primary language:
Function(r As IDataReader) As New List(Of RawTie)
Dim ties As New List(Of RawTie)()
Do While r.Read()
'Do something with the ties
Loop
r.Close()
Return ties
End Function
Is there any information on, at least, whether this is a VB problem or a WWF problem? Just ask if you need more information.

Related

How can I create an "enum" type property value dynamically

I need to create a property in a class that will give the programmer a list of values to choose from. I have done this in the past using the enums type.
Public Enum FileType
Sales
SalesOldType
End Enum
Public Property ServiceID() As enFileType
Get
Return m_enFileType
End Get
Set(ByVal value As enenFileType)
m_enFileType = value
End Set
End Property
The problem is I would like to populate the list of values on init of the class based on SQL table values. From what I have read it is not possible to create the enums on the fly since they are basically constants.
Is there a way I can accomplish my goal possibly using list or dictionary types?
OR any other method that may work.
I don't know if this will answer your question, but its just my opinion on the matter. I like enums, mostly because they are convenient for me, the programmer. This is just because when I am writing code, using and enum over a constant value gives me not only auto-complete when typing, but also the the compile time error checking that makes sure I can only give valid enum values. However, enums just don't work for run-time defined values, since, like you say, there are compile time defined constants.
Typically, when I use flexible values that are load from an SQL Table like in your example, I'll just use string values. So I would just store Sales and SalesOldType in the table and use them for the value of FileType. I usually use strings and not integers, just because strings are human readable if I'm looking at data tables while debugging something.
Now, you can do a bit of a hybrid, allowing the values to be stored and come from the table, but defining commonly used values as constants in code, sorta like this:
Public Class FileTypeConstants
public const Sales = "Sales"
public const SalesOldType = "SalesOldType"
End Class
That way you can make sure when coding with common values, a small string typo in one spot doesn't cause a bug in your program.
Also, as a side note, I write code for and application that is deployed internally to our company via click-once deployment, so for seldom added values, I will still use an enum because its extremely easy to add a value and push out an update. So the question of using and enum versus database values can be one of how easy it is to get updates to your users. If you seldom update, database values are probably best, if you update often and the updates are not done by users, then enums can still work just as well.
Hope some of that helps you!
If the values aren't going to change after the code is compiled, then it sounds like the best option is to simply auto-generate the code. For instance, you could write a simple application that does something like this:
Public Shared Sub Main()
Dim builder As New StringBuilder()
builder.AppendLine("' Auto-generated code. Don't touch!! Any changes will be automatically overwritten.")
builder.AppendLine("Public Enum FileType")
For Each pair As KeyValuePair(Of String, Integer) In GetFileTypesFromDb()
builder.AppendLine(String.Format(" {0} = {1}", pair.Key, pair.Value))
End For
builder.AppendLine("End Enum")
File.WriteAllText("FileTypes.vb", builder.ToString())
End Sub
Public Function GetFileTypesFromDb() As Dictionary(Of String, Integer)
'...
End Function
Then, you could add that application as a pre-build step in your project so that it automatically runs each time you compile your main application.

why can I only access the properties of an anonymous type when I add .toList to the end of my linq query

I'm learning LINQ and VB and just spent an hour trying to access the fields of an anonymous type defined in a linq query. The key (I learned) is to convert the query to a list before you try to iterate through it with a for loop.
How to access property of anonymous type in C#?
This does not work: edit (this compiles, but intellisense does not recognize the type)
Dim varbl=from itm in collct select New With {.n=itm.Name} 'query here
for each returnedItem in varbl
returnedItem.n 'intellisense does not pick up the property names
next
But this does:
Dim varbl=(from itm in collct select New With {.n=itm.Name}).toList
for each returnedItem in varbl
returnedItem.n 'this works
next
Can somebody explain why/what is going on? The (otherwise helpful!) post above just says it is "Because of the way the compiler works, the following then should also work once you have created the list, because the anonymous types have the same structure so they are also the same type. I don't have a compiler to hand to verify this though"
Well, I wasn't going to answer since my VB is both very rusty and pretty out of date (eh, VB6 about a decade ago). But something did seem wrong here from a .NET perspective.
Your read on the answer you link to (which is incomplete in its explanation IMO) is wrong. It's not that you need to put the anonymous object into a list, but that the querent there had been putting it into a List<object> which meant that the compiler couldn't tell what properties it had (it's dealing with an object not an object of the anonymous type in question, and object doesn't have a Checked property).
Anyway. I tried writing your initial attempt into some C# as:
private class TestType
{
public string Name{get;set;}
public TestType(string name)
{
this.Name = name;
}
}
public static void Main()
{
TestType[] collct = new TestType[]{new TestType("abc"), new TestType("def"), new TestType("xyz")};
var varbl = from itm in collct select new {n = itm.Name};
foreach(var returnedItem in varbl)
Console.WriteLine(returnedItem.n);
}
Then I compiled and decompiled as VB.NET in reflector, which had my Main as:
Public Shared Sub Main()
Dim collct As TestType() = New TestType() { New TestType("abc"), New TestType("def"), New TestType("xyz") }
Dim varbl = (From itm In collct Select New With { _
.n = itm.Name _
})
Dim returnedItem
For Each returnedItem In varbl
Console.WriteLine(returnedItem.n)
Next
End Sub
Which looks pretty much like your original, doesn't it?
Well, it works; it compiles and runs and gives me correct answers.
The only thing I can think of is that maybe IntelliSense just wasn't on the ball here. I have found that some times in the past, IntelliSense struggles to suggest the property names of anonymous types, and while I use SharpDevelop to code C# rather than VB (in whatever IDE it is that you use), this could be the case here - you actually had the correct code all along, but IntelliSense didn't realise it.
At the end of the day, IntelliSense is pretty darn good, but it's not the compiler, and it can't spend as much resources doing stuff as the compiler for risk of slowing us down while we type.
Incidentally, you should not call ToList unless you actually need a list for your purposes. Imagine if collct was a loaded-as-needed enumeration that would return thousands of objects on the back of loading something from a database or file.
If you don't call ToList, then you will start iterating through them as soon as the data for the first one arrives, and you'll only need to use memory for a handful at a time.
If you do call ToList, then program will be stuck at that line until it's loaded every single object into a massive list in memory, and only then start your For Each.
Of course, there are times when you do need to be able to move back and forward though a list, or to know the count before you iterate, and then it's certainly better to call ToList than to keep repeating the For Each, but if you don't know you need it, don't use it.

Implement LINQ to SQL expressions for a database with custom date/time format

I'm working with an MS-SQL database with tables that use a customized date/time format stored as an integer. The format maintains time order, but is not one-to-one with ticks. Simple conversions are possible from the custom format to hours / days / months / etc. - for example, I could derive the month with the SQL statement:
SELECT ((CustomDateInt / 60 / 60 / 24) % 13) AS Month FROM HistoryData
From these tables, I need to generate reports, and I'd like to do this using LINQ-to-SQL. I'd like to have the ability to choose from a variety of grouping methods based on these dates (by month / by year / etc.).
I'd prefer to use the group command in LINQ that targets one of these grouping methods. For performance, I would like the grouping to be performed in the database, rather than pulling all my data into POCO objects first and then custom-grouping them afterwords. For example:
var results = from row in myHistoryDataContext.HistoryData
group row by CustomDate.GetMonth(row.CustomDateInt) into grouping
select new int?[] { grouping.Key , grouping.Count() }
How do I implement my grouping functions (like CustomDate.GetMonth) so that they will be transformed into SQL commands automatically and performed in the database? Do I need to provide them as Func<int, int> objects or Expression<> objects, or by some other means?
You can't write a method and expect L2S to automatically know how to take your method and translate it to SQL. L2S knows about some of the more common methods provided as part of the .NET framework for primitive types. Anything beyond that and it will not know how to perform the translation.
If you have to keep your db model as is:
You can define methods for interacting with the custom format and use them in queries. However, you'll have to help L2S with the translation. To do this, you would look for calls to your methods in the expression tree generated for your query and replace them with an implementation L2S can translate. One way to do this is to provide a proxy IQueryProvider implementation that inspects the expression tree for a given query and performs the replacement before passing it off to the L2S IQueryProvider for translation and execution. The expression tree L2S will see can be translated to SQL because it only contains the simple arithmetic operations used in the definitions of your methods.
If you have the option to change your db model:
You might be better off using a standard DateTime column type for your data. Then your could model the column as System.DateTime and use its methods (which L2S understands). You could achieve this by modifying the table itself or providing a view that performs the conversion and having L2S interact with the view.
Update:
Since you need to keep your current model, you'll want to translate your methods for L2S. Our objective is to replace calls to some specific methods in a L2S query with a lambda L2S can translate. All other calls to these methods will of course execute normally. Here's an example of one way you could do that...
static class DateUtils
{
public static readonly Expression<Func<int, int>> GetMonthExpression = t => (t / 60 / 60 / 24) % 13;
static readonly Func<int, int> GetMonthFunction;
static DateUtils()
{
GetMonthFunction = GetMonthExpression.Compile();
}
public static int GetMonth(int t)
{
return GetMonthFunction(t);
}
}
Here we have a class that defines a lambda expression for getting the month from an integer time. To avoid defining the math twice, you could compile the expression and then invoke it from your GetMonth method as shown here. Alternatively, you could take the body of the lambda and copy it into the body of the GetMonth method. That would skip the runtime compilation of the expression and likely execute faster -- up to you which you prefer.
Notice that the signature of the GetMonthExpression lambda matches the GetMonth method exactly. Next we'll inspect the query expression using System.Linq.Expressions.ExpressionVisitor, find calls to GetMonth, and replace them with our lambda, having substituted t with the value of the first argument to GetMonth.
class DateUtilMethodCallExpander : ExpressionVisitor
{
protected override Expression VisitMethodCall(MethodCallExpression node)
{
LambdaExpression Substitution = null;
//check if the method call is one we should replace
if(node.Method.DeclaringType == typeof(DateUtils))
{
switch(node.Method.Name)
{
case "GetMonth": Substitution = DateUtils.GetMonthExpression;
}
}
if(Substitution != null)
{
//we'd like to replace the method call; we'll need to wire up the method call arguments to the parameters of the lambda
var Replacement = new LambdaParameterSubstitution(Substitution.Parameters, node.Arguments).Visit(Substitution.Body);
return Replacement;
}
return base.VisitMethodCall(node);
}
}
class LambdaParameterSubstitution : ExpressionVisitor
{
ParameterExpression[] Parameters;
Expression[] Replacements;
public LambdaParameterExpressionVisitor(ParameterExpression[] parameters, Expression[] replacements)
{
Parameters = parameters;
Replacements = replacements;
}
protected override Expression VisitParameter(ParameterExpression node)
{
//see if the parameter is one we should replace
int p = Array.IndexOf(Parameters, node);
if(p >= 0)
{
return Replacements[p];
}
return base.VisitParameter(node);
}
}
The first class here will visit the query expression tree and find references to GetMonth (or any other method requiring substitution) and replace the method call. The replacement is provided in part by the second class, which inspects a given lambda expression and replaces references to its parameters.
Having transformed the query expression, L2S will never see calls to your methods, and it can now execute the query as expected.
In order to intercept the query before it hits L2S in a convenient way, you can create your own IQueryable provider that is used as a proxy in front of L2S. You would perform the above replacements in your implementation of Execute and then pass the new query expression to the L2S provider.
I think you can register your custom function in the DataContext and use it in the linq query. In this post is very well explained: http://msdn.microsoft.com/en-us/library/bb399416.aspx
Hope it helps.
Found a reference to some existing code which implements an IQueryable provider as Michael suggests.
http://tomasp.net/blog/linq-expand.aspx
I think assuming that code works, the other lingering issue is that you would have to have an Expression property for each type which contained the date.
The resulting code for avoiding doing that appears to be a bit cumbersome (though it would avoid the sort of errors you're trying to avoid by putting the calculation in a method):
Group Expression:
group row by CustomDate.GetMonth(row, x => x.customdate).Compile().Invoke(row)
Method to Return Group Expression:
public class CustomDate
{
public static Expression<Func<TEntity, int>> GetMonth<TEntity>(TEntity entity, Func<TEntity, int> func)
{
return x => ((func.Invoke(entity)/60/60/24)%13);
}
}
I'm not entirely sure whether that nested .Invoke would cause problems with the Expandable expression or whether the concept would have to be tweaked a bit more, but that code seems to supply an alternative to building a custom IQueryProvider for simple mathematical expressions.
There doesn't appear to be any way to instruct LINQ-to-SQL to call your SQL UDF. However, I believe you can encapsulate a reusable C# implementation in System.Linq.Expressions.Expression trees...
public class CustomDate {
public static readonly Expression<Func<int, int>> GetMonth =
customDateInt => (customDateInt / 60 / 60 / 24) % 13;
}
var results = from row in myHistoryDataContext.HistoryData
group row by CustomDate.GetMonth(row.CustomDateInt) into grouping
select new int?[] { grouping.Key , grouping.Count() }

.NET - Is there a way to programmatically fill all tables in a strongly-typed dataset?

I have a SQL Server database for which I have created a strongly-typed DataSet (using the DataSet Designer in Visual Studio 2008), so all the adapters and select commands and whatnot were created for me by the wizard.
It's a small database with largely static data, so I would like to pull the contents of this DB in its entirety into my application at startup, and then grab individual pieces of data as needed using LINQ. Rather than hard-code each adapter Fill call, I would like to see if there is a way to automate this (possibly via Reflection).
So, instead of:
Dim _ds As New dsTest
dsTestTableAdapters.Table1TableAdapter.Fill(_ds.Table1)
dsTestTableAdapters.Table2TableAdapter.Fill(_ds.Table2)
<etc etc etc>
I would prefer to do something like:
Dim _ds As New dsTest
For Each tableName As String In _ds.Tables
Dim adapter as Object = <routine to grab adapter associated with the table>
adapter.Fill(tableName)
Next
Is that even remotely doable? I have done a fair amount of searching, and I wouldn't think this would be an uncommon request, but I must be either asking the wrong question, or I'm just weird to want to do this.
I will admit that I usually prefer to use unbound controls and not go with strongly-typed datasets (I prefer to write SQL directly), but my company wants to go this route, so I'm researching it. I think the idea is that as tables are added, we can just refresh the DataSet using the Designer in Visual Studio and not have to make too many underlying DB code changes.
Any help at all would be most appreciated. Thanks in advance!
I saw all above solutions and they all are good, they inspired me to find my solution,
I made a more squeezed one, I know this is an old post, but I hope it helps people in the time to come,
Private Sub FillDataSet(ByRef ds As SvuDS)
For Each t As DataTable In ds.Tables
Dim adType As Type = Assembly.GetExecutingAssembly.GetType("ProjectNameSpace.MyDSTableAdapters." & t.TableName & "TableAdapter")
'Create Adapter Instance
Dim adapter As Object = Activator.CreateInstance(adType)
'Fill the Table
adapter.GetType().GetMethod("Fill").Invoke(adapter, New Object() {t})
Next
End Sub
I could've even inferred the namespace somehow too, but I wanted it to be simple, and it worked for me
There does not exists any api that lets you do this auto-fill of the entire typed-dataset or no such code is generated within typed-dataset that supports this. It is also difficult to do this because TableAdapters do not have a common base-class that can let you do this.
If you really need to do this, you'll have to maintain a collection of DataTable type-names and TableAdapter type-names and iterate over the collection to perform the dataset fill.
So I recommend to fill dataset for each table in 'hard-code' manner as your first code examples states.
EDIT
Here's one possible solution.
Define an Interface ITableAdapter as following
public interface ITableAdapter<TDataTable> : where TDataTable : DataTable
{
TDataTable SelectAll();
}
All TableAdapters are partial classes, so you can extend them and add your custom code in partial custom class for TableAdapter. Implement ITableAdapter on each TableAdapter in your typed-data-set. so it might look like this.
public partial class YourTableAdapter : ITableAdapter<YourDataSet.YourDataTableDataTable>
{
public YourDataSet.YourDataTableDataTable SelectAll()
{
return this.GetData();
}
}
Now, you can iterate over each type in your assembly and filter those of type ITableAdapter and call SelectAll() method on each of them fill it into your Dataset. :)
EDIT2
I just came up with another elegant solution for this problem. All you need to do is define the Interface ITableAdapter to map the already implemented methods in TableAdapters that are generated by the dataset-designer.
public interface ITableAdapter<TDataTable> : where TDataTable : DataTable
{
void Fill(TDataTable);
}
And extend your TableAdapter partial classes like this.
public partial class YourTableAdapter : ITableAdapter<YourDataSet.YourDataTableDataTable>
{
//No code required here, since Fill method is already defined in TableAdapter :)
}
OK, I think I have this worked out, and just want to share the results on the off chance that there are people out there who are as insane as I am.
Basically, all the magic happens using a couple of LINQ queries and reflection. For the purposes of this example, we will assume:
There is a strongly-typed DataSet created using the DataSet Designer in Visual Studio 2008, called dsTest. A module-level variable holds an instance of this DataSet and is called (appropriately enough), m_DataSet.
The tables themselves all follow a standard SQL Server naming convention, starting with "tbl".
As a part of this wizard, a series of table adapters were created for each table inside a namespace called dsTestTableAdapters.
Each adapter is named according to the table (so if we have "tblThingy", then an adapter named "tblThingyTableAdapter" would be created).
The application is in a namespace called, for lack of anything better, MyNamespace.
Here's the routine, called on Form Load:
Private Sub PopulateDataSet()
' Get our table adapters
Dim adapters As List(Of Type) = (From t As Type In System.Reflection.Assembly.GetExecutingAssembly.GetTypes Where t.Namespace = "MyNameSpace.dsTestTableAdapters" And t.Name.StartsWith("tbl") Select t).ToList
' Initialize our dataset
m_DataSet = New dsUtility
' Get our table names
Dim tableNames as List(Of String) = (From dtbl As DataTable In m_DataSet.Tables Select dtbl.TableName).ToList
' Loop through each table name and fill the table with the corresponding adapter
For Each iter As String In tableNames
' Grab the corresponding adapter name
Dim tableName As String = iter ' Grab a copy of the table name to avoid LINQ issues with iteration variables
Dim adapterType As Type = (From t As Type In adapters Where t.Name.StartsWith(tableName) Select t).First
' Given the adapter type name, use Reflection to create an instance
Dim adapter As Object = Activator.CreateInstance(adapterType)
' Use the instance to fill the appropriate table
adapter.Fill(m_DataSet.Tables(tableName))
Next
End Sub
I tried that, and it worked like a charm. Thanks, everyone, for your help and I hope you find this useful!
I think You have only one problem !
if this Typed dataset has relations between tables, this code won't load the datatables in the correct order !
Thanks, Mike, for the very thoughtful solution. Like you, I have been searching for a way to do what you've done, and to use the same mechanism to avoid an ugly switch statement (in C#) that has to case the generated TableAdapters to perform data binding updates.
I converted your VB code to C# as noted below. I made two changes (I'm using VS Express 2010 and .NET 4.0):
I changed the StartWith("tbl") method to EndsWith("TableAdapter") since a number of generated members in the TableAdapters namespace other than just the TableAdapters begin with "tbl" (assuming you want or need to follow that convention anyway), but only the TableAdapters end with "TableAdapter."
I changed the call to the Fill method since VS tells me at build time that the object referenced by "adapter" (which does look like a TableAdapter in the debugger) doesn't have a Fill method and there is no Fill extension method. I therefore cannot perform the Fill. I'm not at all sure why this didn't work. But in any case, I changed it to explicitly find the Fill method and then invoke that method. That seems to work.
Steve
public PopulateDataSet ()
{
// Get the TableAdapters
List<Type> tableAdapters = (from t in
System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
where t.Namespace == "MyNameSpace.m_DataSetTableAdapters"
&& t.Name.EndsWith("TableAdapter")
select t).ToList();
// Get the DataTable names
List<string> tableNames = (from DataTable dtbl in m_DataSet.Tables
select dtbl.TableName).ToList();
// Loop thru each table and fill it using the corresponding TableAdapter
foreach (string iter in tableNames)
{
string tableName = iter; // Stopt Linq issues with iteration vbls
Type adapterType = (from t in tableAdapters
where t.Name.StartsWith(tableName)
select t).First();
// Given the adapter type name, use Reflection to create an instance
Object adapter = Activator.CreateInstance(adapterType);
// Get a reference to the Fill method of the relevant adapter
MethodInfo method = adapter.GetType().GetMethod("Fill");
// Invoke the Fill method, passing in the relevant DataTable parameter
method.Invoke(adapter, new Object[] {m_DataSet.Tables[tableName]});
}
}
Some time ago I've found this thread and since then use this approach with success in my small project. But, recently I've found it out a bit limited. I have few queries for each table adapter in a data set with the names like "FillByContext", "FillById", "FillByName", etc., each one with a different set of parameters of different data types. All methods return tables with the same structure, but with different contents. So that I added some small "generalization" to the approach.
Private Sub MethodsAndParams(ds As DataSet,
dt As DataTable,
taParams() As Object,
taMethod As String)
Dim taType As Type = Assembly.GetExecutingAssembly.GetType(
"MyProjectName." +
ds.DataSetName +
"TableAdapters." +
dt.TableName +
"TableAdapter")
Dim ta As Object = Activator.CreateInstance(taType)
dt = ds.Tables(dt.TableName)
ta.GetType().GetMethod(taMethod).Invoke(
ta, New Object() {dt}.Union(taParams).ToArray)
End Sub
Now I can pass table adapter method names as strings and appropriate parameter sets as arrays of objects to this routine.

How do I run an HqlBasedQuery that returns an unmapped list of objects using nHibernate?

I want to run a query against two tables (which happen to be mapped in ActiveRecord). The query returns a result list that cannot be mapped to an ActiveRecord object (as it is custom aggregate information).
For instance
Dim query_str as string = "Select distinct d.ID, (select count(1) as exp from Sales_Leads where date_created <= :todays_date) as NbrLeads from Dealer d"
Dim q As Queries.HqlBasedQuery = New Queries.HqlBasedQuery(GetType(ICollection), query_str)
q.SetParameter("todays_date", DateTime.Today)
Dim i As ICollection = ActiveRecordMediator.ExecuteQuery(q)
What I'm looking for is simple execution of SQL, without an ActiveRecord object returned.
So, ideally, I'd be able to look at i("NbrResults") for each item in the collection.
The error I am getting is:
You have accessed an ActiveRecord
class that wasn't properly
initialized. The only explanation is
that the call to
ActiveRecordStarter.Initialize()
didn't include
System.Collections.ICollection class
Well, this was asked a long time ago but I have a working answer.
public static IList<T> ExecuteQuery<T>(HqlBasedQuery query)
where T : new()
{
query.SetResultTransformer(new NHibernate.Transform.AliasToBeanResultTransformer(typeof(T)));
var results = (ArrayList)ActiveRecordMediator.ExecuteQuery(query);
List<T> list = new List<T>(results.Count);
for (int i = 0; i < results.Count; i++)
{
list.Add((T)results[i]);
}
return list;
}
This will give you back results of type T. Type T can be anything you want. Type T needs a no argument constructor and it needs public fields or properties that match the column names or aliases in the query you build.
We do this all the time. Particularly when you want to use aggregate function in HQL to produce aggregate data.
A companion function will allow you to just pass in your query as a string as well as any positional parameters you might have:
public static IList<T> ExecuteQuery<T, U>(string hqlQuery, params object[] parameters)
where T : new()
{
return ExecuteQuery<T>(new HqlBasedQuery(typeof(U), hqlQuery, parameters));
}
Type U is any type that is a valid ActiveRecord type. It doesn't even have to be one of the types you are referencing. If you want you could replace it will some type you know is gonna be valid int he session and ditch the extra parameter.
Here was my final solution:
Dim query_str As String = "SELECT DISTINCT d.ID, count( l ) from LEAD as l join l.Dealer as d where l.DateCreated >= DATEADD(day, -30, :todays_date) GROUP BY d.ID"
Then obtain the active record session (or NHibernate, still don't even know what is returned here):
Dim sess As ISession = activerecordmediator.GetSessionFactoryHolder().CreateSession(GetType(ActiveRecordBase))
Dim q As NHibernate.IQuery = sess.CreateQuery(query_str)
q.SetParameter("todays_date", DateTime.Today)
Dim i As IList = q.List() ' get results
In the .aspx page, the result can be accessed in a GridView like so:
You're stepping outside the NHibernate paradigm to call down to SQL, which is somewhat against the spirit of ORM. It's not 'bad' per-se, but I'd certainly avoid breaking the abstraction if I could to try to maintain a looser coupling.
You can do what you want with a straight HQL query, which will return a collection of tuples containing the results of your query. I explained how to do this here
Custom query with Castle ActiveRecord
which you might want to have a look at. Even though you must specify a type when you new an HQLBasedQuery, NH is smart enough to know that if you don't select a type instance it should assemble a result-set based on object tuples.
(IMNSHO it's still a bit non-pure - I'd be tempted to try to model this relationship as an object and map it accordingly, but then I'd have to bash the DB into shape to suit the object model and that's not going to fly in all cases.)