Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,640
|
Comments: 51,254
Privacy Policy · Terms
filter by tags archive

Reflection WTF

time to read 3 min | 419 words

This is a major WTF, in my opinon, consider the following code:

using System;
public class Program
{
 static void Main()
 {
  Console.WriteLine( "Is Public: {0}"typeof(Inner).IsPublic );
  Console.WriteLine( "Is Not Public: {0}"typeof(Inner).IsNotPublic );
 }
 
 public class Inner {}
}

Without compiling this, can you hazzard a guess about what is the result of this program?

Don't bother, here it is:

Is Public: False
Is Not Public: False

In a stunning misuse of their own guidlines and the English langauge, those are actually not mirror images of each other. Furthermore, check out the documentation for those properties:Type.IsPublic and Type.IsNotPublic. Ignore the documentation at the top of the page, it flat out misleading, check the Property Value section, it contains such gems as (IsNotPublic):

true if the Type is not declared public and is not a nested type; otherwise, false.

So, I can change the visibility of Inner to private, and the output remains the same. IsXXX is a well defined notation, this just completely breaks it. The issue here is the use of TypeAttributes to get the value, and TypeAttributes make a distiction between Public and NestedPublic, but why the hell do they take this distinction to the IsXXX properties. Either the value is public or it isn't, don't go put nesting issues there when you call the property IsPublic.

 

time to read 22 min | 4297 words

Often, when introducing NHibernate, I need to integrate with existing database and infrastructures. Leaving aside the question of stored procedures (since I already expanded on that in length here), which are avialable on NHibernate 1.2, I want to focus on using SQL Functions here.

(One again, I'm back to the Blog -> Posts -> Comments model)

Now, there are four types of SQL Functions that you might want to use:

  • Scalar functions that are a part of an entity.
    A post's total  spam score may be calculated using a SQL Function, and it is part of the properties of the object.
  • Scalar functions that are used for calculations, and should be called explicitly.
    A blog's popularity score may be calculated using a SQL Function, but it is too expensive to calculate and not often needed.
    Note: Only this requires NHibernate 1.2, all other features can be done using NHibernate 1.0.2
  • Table valued functions (or stored procedure, for that matter, but that is a bit harder) that return entities:
    A selection of posts with specific spam score it one example.
  • Scalar functions that you want to use as part of your HQL queries.
    For instnace, you may want to use database (or user defined) functions as part of your HQL queries. Think lower(), dbo.postSpamScore(), etc.

Let us attack each of those in turn, shall we?

First, we have a scalar function that is a property of the entity, in this instance a post' spam score. The SQL Function is defined so:

CREATE FUNCTION GetPostSpamScore ( @postId INT )

RETURNS INT AS BEGIN

      RETURN 42

END

Not very exciting, I know, but for our purposes, it is enough. Now, I need to define the following in the mapping file:

<

property name='SpamScore' formula='dbo.GetPostSpamScore( post_id )'/>

The formula attribute is very powerful, you can even put SQL statements that will be executed as corelated sub queries (if you database supports it).

Q: Hi, what about aliasing? If I use this and join against another table that has a post_id (for instnace, the comments table), won't I get an error or unpredictable results?
A: No, NHibernate will automatically pre-pend the alias of the current entity table to anything that looks like a unqualified column access. If you need a column from another table, make sure to use the column with the qualifying name.

That is all you need to do to get the value from the function into your entities. In fact, you can now even perform HQL queries against this property, like this:

from Post p where p.SpamScore > 50

Second case, we want to get a scalar result from the database, and we are not interested in using ADO.Net directly to do so. Note that this is only possible with NHibernate 1.2, in NHibernate 1.0.2, you will need to use ADO.Net calls directly. Again, the SQL Function is very simple (for demonstration only, you can do anything you want in the SQL function, of course)

CREATE FUNCTION GetBlogTotalSpamScore ( @blogId INT )

RETURNS INT AS BEGIN

      RETURN 42

END

Now, let us map this query so it would be easy to use...

<sql-query name='BlogSpamScore'>

       <return-scalar column='SpamScore' type='System.Int32'/>

       <![CDATA[

              select dbo.GetBlogTotalSpamScore(:blog) as SpamScore

       ]]>

</sql-query>

And the code that uses this:

int spamScore = (int)session.GetNamedQuery("BlogSpamScore")

       .SetEntity("blog", blog).UniqueResult();

A couple of points here. Notice that we are using the NHibernate notations for parameters in the query (:blog), and that we are passing an object to the query, not the identifier. I find this style of coding far more natural and OO than the equivalent ADO.Net code. For that matter, the equivalent ADO.Net code goes on for half a page or so... :-)

Third case, using a table valued function. Table valued function obviously cannot be used as a property of the entity. (To be exact, they can be used as a collection, but this is advanced functionality, and it is only avialable in NHibernate 1.2, so I'm not not going to cover it here). Fairly often, you want to use this for getting a collection of entities from the database using logic that reside in the database (for performance or historic reasons).

Here is my demo function:

ALTER FUNCTION GetAllPostsWithSpamScoreOfAtLeast( @minSpamScore int)

RETURNS TABLE AS RETURN

(

      SELECT post_id, post_blogid FROM Posts

      -- implement WHERE clause here

);

Now, let us map this for a set of entities:

<sql-query name='AllPostsWithSpamScoreOfAtLeast'>

       <return class='NHibernate.Generics.Tests.Post, NHibernate.Generics.Tests'

                     alias='post'/>

       <![CDATA[

              SELECT post_id as {post.PostId}, post_blogid as {post.Blog}, 100 as {post.SpamScore}

              FROM dbo.GetAllPostsWithSpamScoreOfAtLeast(:minSpamScore)

       ]]>

</sql-query>

Notice that I map all the colums to their respective properties (I could also use {post.*} if I wanted all of the columns without bother with specifying each and every one). And that I can pass parameters easily to the query.

Now, I can just query them like this:

IList list = session.GetNamedQuery("AllPostsWithSpamScoreOfAtLeast")

       .SetInt32("minSpamScore", 5).List();

Against this is much more readable than the equivalent ADO.Net code, and I get full fledged objects back. If you want to do projections (show a post summary, etc. Using just part of the entity) you need to map the resulting projection as if it was an entity, NHibernate doesn't support SQL projections. (In practice, this is not an issue).

The last case is using user defined SQL Functions (or bulitin ones that NHibernate doesn't recognize by default) in your HQL queries. In order to do this, you need to either extend the dialect for your database, or dynamically add new functions to the dialect in the session factory (not really recommended). 

Let us assume that you really want the ISOweek function. (See here for the implementation, if you really care). The function declaration is:

CREATE FUNCTION dbo.ISOweek (@DATE datetime) RETURNS INT

I would recommend extending the dialect for the database with the new function, like this:

public class MyDialect : MsSql2000Dialect

{

       public MyDialect()

       {

              RegisterFunction("dbo.isoweek", new StandardSQLFunction(NHibernateUtil.Date));

       }

}

A couple of things to note here. If this is a user defined function, you have to add the schema (in this case, dbo). The function name must be in lower case (HQL is case insenstive, so you can use whatever case you like in the queries, but you register the function with lower case). You then configure NHibernate to your MyDialect instead of your database dialect, and that is it. You can now issue HQL queries like this:

from Post p where dbo.ISOWeek(p.date) = 51

Note that you must still use the "dbo." in the HQL.  Again, you can pass arguments naturally:

session.CreateQuery("from Post p where dbo.ISOweek( :date )  = 12")

.SetDateTime("date", DateTime.Now)

       .List();

(Not that I can't think of a reason why you would want to excute the last two queries).

So, this is just about all you would ever want to know about SQL Functions, and if you kept reading up to now, you are really passionate about it.

Happy (N)Hibernating... :-)

time to read 1 min | 95 words

If you are using NHibernate.Generics with NHibernate 1.2, you may run into casting issues, this is because NHibernate.Generics and NHibernate 1.2 both tries to make the collections generic.

You can either stop using NHibernate.Generics (their main purpose, allowing generic collections in NHibernate) is no longer needed. But their secondary purpose, automatic syncronization between related properties is very nice in many scenarios. Until I'll get around to porting them to 1.2, you need to specify generic="false" in the mapping of all collections that uses NHibernate.Generics for them to work.

time to read 1 min | 83 words

Okay, I'm going to take advantage of having a blog to shorten some religious cycles. If you are not familiar with Yom Kippur, check the wikipedia entry.

If I have hurt, lied, broke my word, disappointed, hated, oppended or angered you*, I am sorry.

* The list in Hebrew goes for amount 15 minutes, it also rhymes. But I don't have the patience to try and translate it all. Sorry for that too.

time to read 1 min | 91 words

I find myself creating it quite a bit, and I got tried of copy/paste to add the item, so I create an item template for VS 2005. You can download it here.

I am thinking about creating a project template as well (I keep creating small projects to test stuff, or abusing my existing NHibernate.Generics project), but I hate the GAC and I don't want hard coded paths in the template. Any ideas how I can add the DLLs themselves to the template?

time to read 2 min | 343 words

You probably know that I am sick of XML configuration, and I devoted some time to allow myself use a real programming langauge (Boo) for my configuration. (See my posts about Binsor for the details). This tend to reduce configuration cruft by an order of magnitude.

That said, having a programming language at my disposable for configuration opens up some interesting possibliites. For one thing, the line that divide the application setup responsability is becoming blur. What do I mean by that?

Well, I got an application that for a particular client, need to map some drives before it can start running. If I were using XML configuration I would probably have some optional configuration entries, code that reads them and then execute it. Using Binsor, I can just make the call to map the drives from the configuration file.

Here is a small example:

import

MyApp.Utils from MyApp

DriveMapper

.MapDrive("""Domain\User""", "SecretPassword", """\\network\share""", "W:")

#continue with normal Binsor configuration

Now this is either a powerful technique or a huge anti pattern :-).

For this case, I think that it is a good solution, but I wonder how useful this is going to be in a more general sense.

time to read 2 min | 211 words

Related to the previous post, I present you a simple SP that is highly vulnerable to SQL injections, and is directly related to my statement about evil sadistics bastards.

ALTER

PROCEDURE GetDataForDate
   @date
DATETIME
AS
  
DECLARE @sql nvarchar(max)
  
SET @sql = 'select * from data_' + convert(nvarchar(30),getdate(),112)
   
EXEC sp_executesql @sql

I think you can deduct what the rest of the system looked like, and what fun it was optimizing the reports that run over data gathered for years.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. API Design (10):
    29 Jan 2026 - Don't try to guess
  2. Recording (20):
    05 Dec 2025 - Build AI that understands your business
  3. Webinar (8):
    16 Sep 2025 - Building AI Agents in RavenDB
  4. RavenDB 7.1 (7):
    11 Jul 2025 - The Gen AI release
  5. Production postmorterm (2):
    11 Jun 2025 - The rookie server's untimely promotion
View all series

Syndication

Main feed ... ...
Comments feed   ... ...