CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Peter's Gekko

public Blog MyNotepad : Imho { }
  • Valid date-time values in sql server. SqlDateTime vs DateTime

    You cannot store every date in sql server. The valid range of dates is from 1/1/1753 (1-1-1753) to 12/31/9999 (31-12-9999). The range of the .NET DateTime type is far larger. So before storing a datetime in a sql server database you have to perform a check. This should be (and is) not to difficult in .NET. But as the documentation of SqlDateTime and other Google results are confusing hereby a quick summary.

    The .NET framework has two types, DateTime and SqlDateTime The SqlDateTime type has implicit operators which convert a sql datetime into a regular DateTime. Thanks to this implicit type conversion you can mix both date types in an expression. At first sight the follwing code looks like a good check.

    DateTime bla = DateTime.MinValue;
    if ((bla >= SqlDateTime.MinValue) && (bla <= SqlDateTime.MaxValue))
    {
        // bla is a valid sql datetime
    }
    

    To my initial surprise it throws a sql exception: "System.Data.SqlTypes.SqlTypeException: SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM." What happens is that before comparing the date the variable bla will be (due to the implicit operator) cast to SqlDateTime. Doing that it will hit the the sqlexception. The rule is that in an expression with two different types they are converted to the narrowest of the two. So what will work is explicitly cast the SqlDateTime to a DateTime. Like this

    DateTime bla = DateTime.MinValue;
    if ((bla >= (DateTime)SqlDateTime.MinValue) && (bla <= (DateTime) SqlDateTime.MaxValue))
    {
        // bla is a valid sql datetime
    }

    This behavior will not show up until the test meets an invalid sql date at runtime.The good thing is that this same kind of implicit conversion can prevent a compile.

    
    

     

    The message is enigmatic until you start realizing that the implicit conversion of date leads to a different type for the result of the expression. A SqlBool instead of a .NET bool.

    This function builds and runs well.

    static bool isValidSqlDate(DateTime date)
    {
        return ((date >= (DateTime)SqlDateTime.MinValue) && (date <= (DateTime)SqlDateTime.MaxValue));
    }
    

    Far easier than the many parsing and testing frenzy I found Googling on this.

  • Holiday postcard, Turkish internet cafe's

    Almost holiday. To get in the mood two holiday postcards shot last holiday in Bodrum, Turkey.

    Colorfull as everything in Turkey. I didn't check inside, promised myself to stay off line for the entire holiday to read myself into deeper insight. The local ATM's did promise a smooth and fast net.

    This is also an answer to a somewhat enigmatic Turkish comment on a picture of Charles Petzold. Where is the man ? Right here !

    Enjoy your holidays !

  • VisualSVN and TortoiseSVN

    Almost holiday time, time to tidy up all work. Recently I moved to Tortoise SVN for all my source control needs. Getting that to work was not that difficult, but to keep it up and running for my set of Visual Studio solutions took a little more effort than I had hoped. The enormous amount of "hidden" files tools like Resharper, nHibernate and VS itself leaves on your disk takes a lot of maintenance. Tortoise SVN has an an exclude files list, this kept growing and growing. Did you know there are CACHE, cache and Cache files ? (Yes you can use expressions in the exclude list) Things got worse when a deployment project was added. Switching from a debug to a build version was enough to get in an endless number of requests for a cleanup and "X is not a working copy directory" error messages.

    Instead of diving deep into SVN configuration I gave Visual SVN a try. This is an add-on for Visual Studio which integrates subversion into Visual Studio. Its is a commercial product. A 30 day full functional trail and $49 for a license. With the current Euro-Dollar exchange rate the ROI was almost instantaneous.

    Visual SVN requires the latest Tortoise SVN to be installed. TortoiseSVN has a built in "check for updates" and considered itself fully up to date at version 1.48. The VisualSVN setup didn't go for less than 1.50, thank goodness the link built into the setup started the required update. After a reboot (due to the windows shell integration of TortoiseSVN) Visual SVN installed without a glitch in both Visual Studio versions it found on my machine, 2005 and 2008.

    Visual SVN takes a more subtle approach than Tortoise SVN. In TSVN I just submitted the whole folder to a repository and set the files to exclude in a filter. With VSVN you submit a solution to SVN from a VS (context) menu. VSVN will create the repository for you and submit just the needed files. No more, no less. End of filter hell. End of working folder hell.

    Before creating a nice new clean repository I had to get the code out of the existing messed up one. This took a little effort. You can copy or move sources under SVN control around. The good thing is that SVN will keep track of the underlying repository. The bad thing is that the way to get rid of this repository binding is well hidden in the docs. To un-version a source you have to export it to itself. In the context menu select Tortoise SVN | Export. When prompted for a directory pick the source directory itself. SVN will prompt "Do you want to make this working copy unversioned?". A confirmation will free the source by removing the svn information.

    VisualSVN works very well together with TortoiseSVN. You can view and do everything from both Visual Studio and the Windows Explorer with SVN.

    No big difference. What I like far better in VS are the overlay icons. They a far more subtle than the default Tortoise SVN ones. And they update immediately after a status update. In the Windows explorer they really lag behind (on my Vista machine). Displaying the right icons often requires reopening the explorer window.

    That's it, another improvement of my toolbox. And all sources ready for holiday.

  • SQl server reporting services versions, Visual Studio versions and asp.net versions. Gotcha.

    Reports are not my favorite part of an application. But to may an end user the reports are the most valuable parts of the system. They are a well presented and clear overview of hours, even days, of work behind the keyboard. So taking good care of the reports is important. A part of my personal dislike is caused by the tools. Crystal Reports was a sheer nightmare. MS Sql Reporting services (RS) is far better but is still a little pale compared to the rest of my toolset.

    Visual Studio 2008 looks like the ultimate environment. In case you are working on an .net 2.0 project that's just a project setting. Net 1.x is a different story, I have a virtual machine to handle that. Alas for reporting services it's a different game. At the moment VS 2008 cannot create or import reporting projects. Period. But the situation is a little more complicated than waiting for the service pack. Let's investigate.

    RS is part of an MS sql server installation. To the report consumers RS is just a web site. In a default install this web site is an asp.net application which runs in IIS on the sql server machine. The RS web app stores all report data in an own instance of sql server. That scenario is not acceptable for a lot of organizations. The RS web site will live in the DMZ but a database server should be far away behind a firewall. Thank goodness the data for the reports do not have to live in the same db server as RS. They can be anywhere, in any format. All the report needs is a connection string. As the RS database is only used by the web app on the same machine there are a lot of ways to hide the db server to the outer world. All interaction, including uploading reports, is done through the web site.

    So setting up RS requires another sql server license. As far I have read al the docs it could be possible to set up RS in such a way that it will use a database on another server. But as configuring reporting services is tricky enough as it is I have skipped this option.

    RS is a part of several sql server versions: sql 2000, sql 2005 and sql 2008. Installing sql 2000 will result in an asp.net 1.1 web application, installing 2005 will result in an asp.net 2.0 web application. I am not sure about 2008, that's well hidden in the docs. As moving to another version of a database server is a far bigger step than moving an application to another .NET version I don't have any hand on experience yet.

    We experienced quite a gotcha when we upgraded a web application to asp.net 2.0. All went well until we arrived at the RS part. The server is an old reliable Windows 2000 server with sql 2000 RS. The main problem is that Windows 2000 cannot run two different asp.net versions (2.0 for the application 1.1. for RS 2000) in the same web site. That takes server 2003. So upgrading the app requires upgrading either the RS to 2005 or even the complete OS to 2003.

    Another gotcha is in the report definitions. It takes Visual Studio to create and edit report definitions. The existing reports were all built using VS 2003 and worked good enough on RS 2000. (Given the many little quirks I talked about in other posts). VS 2008 does not accept a reports project, VS 2005 does. But when importing the project it converts the report definitions. After that RS 2000 no longer understands the reports. RS 2005 does.

    Given all this we have several options

    • Dive into configuration hell
    • Stay with RS 2000. Which will require an upgrade of the server OS and we have to keep VS 2003 alive
    • Move to RS 2005. It is a big step to move to another DB server version. But as it is only on the web server that should be manageable. We have to keep VS 2005 alive. Or not move to 2008 yet.
    • Wait for RS 2008 and VS 2008 integration. Not an option, it should have been operational yesterday.

    My main problem with RS is that it ties my application to stricter versions of it's infrastructure than I had believed. I've been too naive again and any advice is more than welcome.

    Posted Jun 18 2008, 11:48 AM by pvanooijen with 5 comment(s)
    Filed under:
  • What really went wrong ? Check the inner exception

    In his recent overview on Exceptions Karl briefly mentioned the inner exception. By passing an exception to the constructor of the new exception, the exception passed in becomes the new exception's InnerException property.

    private void workWithFile()
    {
        try
        {
            // do something        
        }
        catch (FileNotFoundException ex)
        {
            throw new Exception("Cannot find the file", ex);
        }
    }
    Code using this method can catch the exception
    try
    {
        workWithFile();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

    Now this exception caught here does not contain very much useful information. It would be interesting to know the name and location of the missing file. To get at that you have to inspect the inner exception.

    try
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        FileNotFoundException fnfEx = ex.InnerException as FileNotFoundException;
        if (fnfEx != null)
            Console.WriteLine(fnfEx.FileName);
    }

    Instead of discussing the design issues here (drop the catch in the method and just catch a  FileNotFoundException in the consuming code) I want to take a look on a situation in real life where the inner exception does tell the story.

    When initializing a sessionfactory in nHibernate a lot of things can go wrong and will throw an exception. My nHibernatemanger does not handle any of them, so my code will have to check. At first sight this might look OK

    try
    private void reportException(Exception ex)
    {
        Console.Write("* ");
        Console.WriteLine(ex.GetType().ToString());
        Console.WriteLine(ex.Message);
        Console.WriteLine();
    }
    
    [Test]
    public void CanReportOuterException()
    {
        try
        {
            INhibernateHelper nhh = GetNHhelper();
        }
        catch (Exception ex)
        {
            reportException(ex);    
        }
    }

    Running the code will not make me much wiser

    Also here the real information is in an inner exception. As each (inner) exception can have another innerexception my code is going to handle every inner exception it can find

    [Test]
    public void CanReportAllExceptions()
    {
        try
        {
            INhibernateHelper nhh = GetNHhelper();
        }
        catch (Exception ex)
        {
            while (ex != null)
            {
                reportException(ex);
                ex = ex.InnerException;
            }
        }
    }

    A stack of three exceptions turn up. Together they describe very well what really went wrong. In this case I misspelled the name of the mapping assembly.

    I have "misused" resharpers unit test runner to develop this code. In fact the result is much like the testrunner's report on handling an exception not caught by a test.

    [Test]
    public void CanCreateHelper()
    {
        INhibernateHelper nhh = GetNHhelper();
        Assert.IsNotNull(nhh);
    }

    Note that the runner lists the exception the other way round, starting at the most inner exception.

    Instead of delving though the stack of exceptions you could use the ToString() method of the exception. Which results in a bulky string including information on the inner exceptions and more. But this info is not as well structured and misses the type info of the inner exceptions.

    I'm not quite sure why nHibernate does wrap its exceptions this way, but what I have learned is to look inside.

    Posted Jun 10 2008, 11:10 AM by pvanooijen with 1 comment(s)
    Filed under:
  • The end of the era of magic (I want coaches, not wizards)

    Five years and one day ago I wrote my first blogpost. Blogging has done more to and for me than I could ever imagine so this celebration is worth a little rant on a subject which has changed most over these years.

    Five years ago I was still with one foot in the Delphi world. Delphi was at the time where the terms RAD and wizard were considered qualities of great value. These days saying these words alone is enough to light the flames. What has changed ? The essential part is imho that In Delphi the RAD designers and wizards were two way tools. You launch the wizard or drop something on a design surface and it will guide you to produce source code. You modify the source code and the wizard or the designer will pick up these changes in the next rounds. So it is you and the wizard working on a shared piece of code. Of course you can do horrible things with such tools, like dropping a sqlconnection directly on a form and all that. But you don't need wizardry to do that, the devil is in the developer himself.

    Arriving in the MS world I found wizards from a quite different guild. They didn't tell me what they were going to do, hid the result in invisible code and did not allow another round. The most hilarious one was "create compatible Guid" in (pre .net)  VB. It took me some time to realize that after every rebuild I of the COM server I had to re-import the typelibrary in the consuming (Delphi) application. Quite recently I encountered a comparable sorcerer when moving some machines to another domain. Trying to do this job as fast as possible I used the Windows migrate settings wizard. Which did work for a lot of things. But it never told me what it had actually migrated, and now once in a while somebody asks me "wtf happened to xxx?". Always surprising. The wizard did produce some messages but these were of the abracadabra kind, only comprehensible to members of the same guild.

    So looking back it is the end of the era of magic. (For those who only recognize starwars quotes, that is from my favorite cult series) Wizards are dead but in the next five years I would love to see the return of the coaches. Thank goodness all it takes to see some of that is refactoring with Resharper. And in VS 2008 the split view designing an aspx page is a RADical improvement.

    Posted Jun 04 2008, 11:51 AM by pvanooijen with no comments
    Filed under:
  • nHibernate many-to-many collections. (OR mapping is not one table one class)

    Mapping collections in nHibernate is at first sight quite confusing. There are loads and loads of possibilities. The official documentation is somewhat academic. This is good because, once you have got it, it is a clear reference. But it is bad because the style does not always help to get it; especially when the docs start saying The previous sections are pretty confusing and try to clarify things with some short examples. Thank goodness there are more resources. Especially parts of an article nHibernate made simple by David Veeneman gave me some "aha-erlebnisse". Here I will recap parts of what I have learned and used for one of my own projects. I have picked this part as well because it does a great job in showing that OR mapping in nHibernate is more than just writing an hbm.xml mapping for every database table.

    Mapping collections

    There are several ways to describe a collection

    • A set contains unique items, the items have no order
    • A bag can contain the same item more than once, the items have no order
    • A list contains ordered items. Each item has an index in the list.

    An nHibernate mapping of a collection can even be in four different forms. Besides these three ways there is a map. A list has an integer index; a map is a list where the index has a complex type.

    These collection types map not that well on the .NET types. There is no set type in .NET and the idea of ordering is implicit. Included in the nHibernate api is Iesi.Collections which does have a set type. But nHibernate can map on just the standard .NET types. For now I will do just that. A set can be mapped to an IEnumerable the others can be mapped to an Ilist. Note that the latter implicitly introduces an order to the items in a bag.

    Mapping a collection in a domain

    I have a website which contains a listing of publications. These publications are categorized in a number of subjects. Every publication can be on several subjects. A clear domain model in code will look like this

    namespace Gekko.Website.Domain
    {
        public class Subject
        {
            public override string ToString()
            {
                return Name;
            }
    
            public virtual int Id { get; set; }
            public virtual string Name { get; set; }
        }
    }
    
    namespace Gekko.Website.Domain
    {
        public class Publication
        {
            public override string ToString()
            {
                return Title;
            }
    
            public virtual int Id { get; set; }
            public virtual bool Hidden { get; set; }
            public virtual string Title { get; set; }
            public virtual string Description { get; set; }
            public virtual string Url { get; set; }
            public virtual bool InDutch { get; set; }
            public virtual Publisher PublishedBy { get; set; }
            public virtual int PublishedInYear { get; set; }
            private IList onSubjects = new List();
            public virtual IList OnSubjects
            {
                get { return onSubjects; }
                set { onSubjects = value; }
            }
        }
    }

    This is a model I can communicate in a clear language with my customer. As stated a publication has a list of subjects.

    When it comes to storing this in a relational database things are more complicated. This is a many to many relation, a publication has several subjects, a subject has several publications. To store this we need three tables. The database will look like this

    The good thing about using nHibernate as an O-R mapper is that I don't need a class for the PublicationOnSubject table. The relation between publication and subject, which is so clear in the model, can be mapped to the underlying database as a collection. The mapping of the subject is straightforward

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Gekko.Website.Domain" namespace="Gekko.Website.Domain">
      <class name="Subject" table="Subjects" proxy="Subject">
        <id name ="Id" type="Int32" column="idSubject">
          <generator class="identity"></generator>
        </id>
        <property name="Name" type="string" length="50" column="Subject"></property>
      </class>
    </hibernate-mapping>

    In the mapping of the publication the subjects are mapped in a many-to-many collection

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Gekko.Website.Domain" namespace="Gekko.Website.Domain">
      <class name ="Publication" table="Publications" proxy="Publication">
        <id name="Id" type="Int32" column="idPublication">
          <generator class="identity"></generator>
        </id>
        <property name="Hidden" type="boolean" column="Hidden"></property>
        <property name ="Title" type="string" length="80" column="Title"></property>
        <property name="Description" type="string" length="150" column="Description"></property>
        <property name="PublishedInYear" type="Int32" column="PublishedInYear"></property>
        <property name ="Url" type="string" length="120" column="Url"></property>
        <property name="InDutch" type="boolean" column="inDutch"></property>
        <many-to-one name="PublishedBy" class="Publisher" column="idPublisher"></many-to-one>
        <bag name="OnSubjects" table="PublicationOnSubject" lazy="false" >
          <key column="idPublication"></key>
          <many-to-many class="Subject" column="idSubject"></many-to-many>
        </bag>
      </class>
    </hibernate-mapping>

    OnSubjects is a bag which uses the table PublicationOnSubject. The key to this linking table is idPublication. The many to many class is the Subject class we just mapped.

    Using the domain objects on a winform

    The Publication and Subject domain objects are easy and clear to use in code. The OnSubjects bag of a publication maps to an Ilist and anything which implements Ilist can be used for databinding. In both classes I have overridden the ToString method to a descriptive property. This will make databinding a snap as the default display of an object is ToString().

    This is some winforms code which combines controller and view. It uses the repositorymanger I presented in an earlier post. When loading the form a list of publications and a list of subjects are read from the repositories and bound directly to the controls. The listbox will display the Names of Subjects.

    repository = new HibernateBasedRepository();
    dataGridView1.DataSource = repository.Publications.ListAll("Title");
    listBoxPotentialCategories.DataSource = repository.Subjects.ListAll("Name");

    Likewise I can bind the OnSubjects property of the selected publication to another listbox

    listBoxAssignedCategories.DataSource = pub.OnSubjects;

    Things get even better when updating the OnSubjects property. Which is a matter of picking a Subject domain object, adding that to the OnSubjects collection of the publication and persisting the publication to the repository.

    pub.OnSubjects.Add(listBoxPotentialCategories.SelectedItem as Subject);
    repository.Publications.Save(pub);
    repository.Commit();

    Deleting a subject is a matter of removing the subject form the OnSubjects collection

    pub.OnSubjects.Remove(listBoxAssignedCategories.SelectedItem as Subject);
    repository.Publications.Save(pub);
    repository.Commit();
    The hard thing is updating the form by notifying the datasource has changed. For the sake of completeness:
    ((CurrencyManager) listBoxAssignedCategories.BindingContext[listBoxAssignedCategories.DataSource]).Refresh();

    I can't make that easier, that's just winforms.

    Winding down

    That's about it. We have been working with a clear model which an end user also understands. In my experience most people do understand how data in information systems is organized in tabular form. But when I start talking about normalized tables we lose each other. Here nHibernate's O-R mapping pushes the technical details of normalization out of the model, even completely out of the code. And also for the developer writing the code work has become clearer and easier. Would you like to write out all sql needed by hand ? Not me.

    Posted May 29 2008, 02:23 PM by pvanooijen with 5 comment(s)
    Filed under:
  • Getting started with subversion

    Good tools are half the job. Being a one person shop I believed VSS was good enough for my source control needs. Almost everybody says Subversion is a far better alternative. The main advantage mentioned is (beside stability and all that) the different and better way subversion handles multiple users working on the same file. As a one person shop that's not that important. The main downside mentioned is a somewhat steep learning curve. But recently, after another frustrating struggle with VSS, I had enough and spent my energy on an exploration of Subversion.

    It was a delight. The learning curve is by far not as steep as I feared. Besides that the documentation included is quite good. My only problem was to find a good starting point. I found this in TortoiseSVN, which presents itself as just a client but does contain everything I need. The help files tell all you want to know about Subversion and more. Here I'll just summarize the things you need for a jumpstart.

    TortoiseSVN presents itself as a shell extension. So it is available in all explorer windows. Subversions stores the sources (or any other file) of a project in a repository. A repository is a folder in the file system. The procedure to create a repository and a working copy is different than VSS, there is no such thing as "Add to source control". You have to create and fill the repository first and create a new working copy after that. These are the steps:

    • Install TortoiseSVN
    • Create a folder to store your repositories. After setting up a repository you will not work with this folder yourself. All interaction runs through the TortoiseSVN shell extensions
    • Setup a template folder. This folder describes the structure of new repositories. Recommended is the trunk/branches/tag tree you meet everywhere in subversion docs.
    • Create new empty folder for the project.
    • Right click it and pick create repository here in the TortoiseSVN context menu. This will fail when the folder is not empty.
    • Select the template folder and pick Import in the TortoiseSVN context menu. You will be asked for a repository. Select the repository folder for the project you just created.
    • Select the folder of the project you want to add to the repository. Again pick Import from the context menu. Select the repository and pick the trunk folder.
    • Create a new empty working folder for the project.
    • In the context menu pick SVN checkout and select the repository. TortoiseSVN will warn when the folder is not empty.

    And now source control is fully integrated in the windows explorer, including all dialogs. An update from or a commit to the repository are just a context click away. TortoiseSVN presents the status of the folder in icon overlays.

    You don't want all files to be under control. Because they muddle up your repository, but also because they spoil the visible status. Just building the project would turn the icon of the root folder red. TortoiseSVN has loads off ways to describe excluded files. I'm still wrestling somewhat with the list. So far I've come up with

    *.dll* *.pdb *.CACHE  _ReSharper.* *resharper* Iesi.Collections.xml Castle.DynamicProxy.xml log4net.xml NHibernate.xml

    But there will be a better way without any doubt. There is also a Visual Studio add-in for SVN, the only Subversion commercial product I know of. (Yes, also subversion is an open source project) But I haven't looked at that yet.

    I have only talked about this client tool. For the moment this does fulfill all my needs. I can reach repositories over the network using a file url like  file://HARAHARA/Users/Peter/SubversionRepositories/Gekko\Website/trunk (mind the (back-)slashes). In case I need more, there is whole load of subversion servers available for any platform.

    That's about it. Another great tool added to my box.

  • Nhibernate and medium trust

    Being sick of all the hassles it took to keep my own server up and running I've moved it to a public hoster. Which does offer asp.net hosting but like many others code is only given medium trust. My site was using nHibernate. That does have serious problems under this trust level. I've been investigating and experimenting to get it up and running. Alas without success. Nevertheless a summary of what I've done. As most web references on this subject are either vague or not specific enough this can help get a better overview. Or perhaps somebody can point me to something I have overlooked.

    Medium trust restricts the permissions given to your code. When googling a lot of the links mention the error message That assembly does not allow partially trusted callers. You can get it  when you sign the assemblies of your site. It depends on your hoster. You used to get that when hibernate tries to load a signed assembly with your domain objects. This can be fixed by setting the AllowPartiallyTrustedCallersAttribute on the loading assembly. This has been fixed on the recent production build of nHibernate; a lot of the posts still around deal with a previous version of nHibernate and are a dead end.

    The main problem with medium trust is that it inhibits reflection. nHibernate depends heavily on reflection. For lazy load to work nHibernate generates proxies to the domain objects. These proxies are built by reflecting on the domain objects. You can configure nHibernate to work without lazy loading. I gave this path a full try and tried everything I could find on the web and could think of myself.

    This is what I did to the configuration

    • Apply the requirepermission="false" in the web.config section of nHibernate
    • Set the hibernate.use_reflection_optimizer in the web.config to false
    • Set the hibernate.bytecode.provider in the web.config to null.

    This is what I did in the mapping files

    • Set the lazy attribute of all classes to "false"
    • Set the lazy attribute of all collections to "false"
    • Remove the proxy attribute of all classes

    In the domain classes I even made all public members non-virtual. In a normal scenario nHibernate will now completely trip over this, complaining it cannot create a proxy.

    On my local machine the site still worked. But on the medium trust host it immediately crashed again on a security exception. The stack trace pointed to the initialization of the reflection optimizer. Huh ? This is where I gave up.

    There is an approach on the web which promises a working lazy load even in medium trust. It is supposed to work by replacing the proxyfactory by one which provides pre generated proxies instead of generating them on the fly via reflection. Alas providing you own proxyfactory takes nHibernate 2.0. Which is still in alpha phase. From a maintainability point of view beyond consideration.

    Googling around getting nHibernate to work under medium trust is considered important but still takes a lot of effort, also in 2.0. I really hope it is going to work but for me it's back to basics for this project. Not all work has to be done again, the domain model is clear, all I have to do is rewrite the implementation of the repositories. To the UI it's not important how I gets the data as long as it gets them.

    The main reason for needing persistence on my site is an index on a selection of my publications. Reading through the results it sometimes does make my toes curl. A lot of the work is pretty old by now and my techniques have really grown over the years. Time for a good update of the contents of the underlying db.

    Posted May 09 2008, 03:35 PM by pvanooijen with 3 comment(s)
    Filed under:
  • Domain-Driven Design: Reading toward deeper insight

    On almost every family holiday I take a good book. Not being distracted by the continuous flow of the Internet and with enough time to let stuff sink in, holiday time makes a good time to see things in perspective again and come home with a fresh mind full off ideas. Last time this worked very well to give myself a real boost on building enterprise applications domain-driven style. Jimmy Nilsson's Applying Domain-Driven Design and Patterns was a quite pragmatic coding based approach which really accelerated my way of building applications. So this time I considered it time to finally do a thorough read of Eric Evans's bible of DDD

    There are plenty of reviews on the web, on Amazon alone you will find loads and loads of information on it's content and value. Besides that it has a website. Fragments of it's content is found in so many posts on Codebetter that it almost seems implicit knowledge over here. But as I enjoyed it that much I would like to draw some more attention to this modern classic itself.

    Inside you will not find a lot of code. Besides that all code is Java code; the .net platform is not even mentioned once. The book is about the essentials of code. All revolves around one central object oriented domain model. A model which serves the developer to write the implementation but it is also a model which speaks the language of the domain expert who understands the required functionality of the software. The model is described in an ubiquitous language whose meaning is understood in the same way by all team members and so serves good communication. By refactoring the developer as well as the domain expert work in cooperation on the same model. This may sound somewhat vague but chapter by chapter all aspects, from database persistence to a vision statement come by including very clear examples. Reading gave me many points of recognition as well as some aha-moments. A very pleasant moment was the conclusion of part 3, Crisis as an opportunity, where Eric mentions "punctuated equilibria", the (r)evolutionary model of a recent rant of mine. How a domain model can evolve over time also fits perfectly in that story.

    At first I only felt sorry I had waited that long to start reading (or going on a holiday :)). The book is written very clear, does give a great overview of the subject and is very systematic in making its point. It is absolutely a classic that every developer, architect (is there a real difference ?) or anyone else who is involved in building software should read. Not everybody does agree on this, between all the five star reviews on Amazon you will find some less enthusiastic ones. So, on second thought, I would not always recommend this book as a starting point for DDD. In case you have troubles reading it start Jimmy Nilsson's Applying DDD and patterns and make sure you really start doing some hands-on DDD stuff yourself. And sooner or later you will really appreciate this book as it will structure all you've read and done back into one clear and flexible model. And that's what DDD is about.

    And now you should start reading it yourself.

  • Jimmy Nilsson is coming to the Netherlands

    Coming april 24th Jimmy Nilsson will be speaking for Dutch user group dotNed. Jimmy is well known for his book Applying Domain-Driven Design and Patterns. A very good aspect of this book is it's style: very easy going and a pleasure to read; but in the meantime you're learning a lot. My first read was on a holiday; on a quite camping place in France. The bad thing about the coming presentation is that it's during another holiday. While Jimmy is talking me and my family will be somewhere half way  between home and a sunny Greek island. Mixed emotions.
  • Wrapping up nHibernate in repositories

    In my last post I discussed wrapping up the two core objects of nHibernate, the sessionmanagerfactory and the session, in a helper class. At the end of the story I briefly mentioned how to use helper objects in a repository. In this post I am further exploring the actual database actions of the helper and how this helper can be used in real repositories in a "regular" DDD style. Again, don't take this as the way to do things. The web is covered with a lot of ways to get that done and there are several tools available. This is just a minimalistic way which works well for me and does demonstrate some programming ideas. Feel free to comment.

    The previous post discussed a way to manage nHibernate sessions. All data operations are performed on such a session. The major operations are described in this interface

    public interface INhibernateHelper : IDisposable

    {

        IQuery Query(string query);

        T UniqueResult<T>(IQuery query);

        IList<T> ListResult<T>(IQuery query);

        IEnumerable<T> EnumerateResult<T>(IQuery query);

        void BeginTransAction();

        void Commit();

        void Save(object dObject);

        void Delete(object o);

    }

    The main reason for describing the functionality as an interface lies in testing; an interface is relatively easy to mock.

    The members which return data are defined as generic methods; this gives me the luxury of strongly typed data. At first sight it might be tempting to make the interface itself generic, that is:

    public interface INhibernateHelper<T> : IDisposable

    {

        T UniqueResult<T>(IQuery query);

    }

    But that will backfire when implementing the interface. To manage a shared sessionfactory I am using a static constructor. As every specific type instance of a generic class fires its own specific static constructor the sessionfactory can no longer be shared over different classes. Having only the methods themselves generic will do.

    When it comes to writing to the database it is important to realize the way nHibernate works. Invoking Save or Delete will not immediately persist that data. It takes the session's Flush method to trigger that. When flushing the data your objects will not always be persisted in the same order as the Save and Delete invocations. Things are further complicated because nHibernate will sometimes perform an implicit flush when querying to prevent returning stale data.

    On a session you can start a transaction but you can only start one transaction on every session. In my implementation of transactions I'm very forgiving. BeginTransaction can be invoked again and again; the first invocation will start the nHibernate transaction. A Commit is always honored; in case no transaction was started the helper will just flush the data.

    The main things when implementing all members is to take care of exceptions. A session cannot recover from an exception. In case you hit one the only solution is to close the session.

    internal class NhibernateHelper : INhibernateHelper

    {

        private static readonly ISessionFactory sessionFactory;

      

        static NhibernateHelper()

        {

            Configuration cfg = new Configuration();

            IDictionary props = new Hashtable();

            props.Add("hibernate.dialect", "NHibernate.Dialect.MsSql2000Dialect");

            props.Add("hibernate.connection.provider", "NHibernate.Connection.DriverConnectionProvider");

            props.Add("hibernate.connection.connection_string", nHibernateConnectionHelper.connectionString);

            cfg.SetProperties(props);

            cfg.AddAssembly(nHibernateConnectionHelper.domainAssembly);

            sessionFactory = cfg.BuildSessionFactory();

        }

      

        private static string connectionString

        {

            get

            {

                Type typeOfConnectionProvider = typeof (NHibernate.Connection.DriverConnectionProvider);

                PropertyInfo ConnectionStringPropertyInfo = typeOfConnectionProvider.GetProperty("ConnectionString",

                                                                                                BindingFlags.Instance | BindingFlags.NonPublic);

                return (string) ConnectionStringPropertyInfo.GetValue(sessionFactory.ConnectionProvider, null);

            }

        }

      

        private readonly ISession currentSession;

      

        internal NhibernateHelper()

        {

            if (string.IsNullOrEmpty(nHibernateConnectionHelper.connectionString))

                throw new Exception("Sessionfactory needs a connectionstring");

            if (nHibernateConnectionHelper.connectionString != connectionString)

                throw new Exception(string.Format("Sessionfactory connection allready initialized as {0}",connectionString));

            currentSession = sessionFactory.OpenSession();

        }

      

        private ITransaction tx = null;

      

        public void BeginTransAction()

        {

            if (tx == null)

                try

                {

                    tx = currentSession.BeginTransaction();

                }

                catch (Exception)

                {

                    currentSession.Close();

                    throw;

                }

        }

      

        public void Commit()

        {

            if (tx == null)

            {

                try

                {

                    currentSession.Flush();

                }

                catch(Exception)

                {

                    currentSession.Close();

                    throw;

                }

      

            }

            else

            {

                try

                {

                    tx.Commit();

                }

                catch (Exception)

                {

                    tx.Rollback();

                    currentSession.Close();

                }

                finally

                {

                    tx = null;

                }

            }

        }

      

        public IQuery Query(string query)

        {

            return currentSession.CreateQuery(query);

        }

      

        public void CloseSession()

        {

            currentSession.Close();

        }

      

        public void Save(object dObject)

        {

            try

            {

                currentSession.SaveOrUpdate(dObject);

            }

            catch (Exception)

            {

                currentSession.Close();

                throw;

            }

        }

      

      

        public void Delete(object o)

        {

            try

            {

                currentSession.Delete(o);

            }

            catch (Exception)

            {

                currentSession.Close();

                throw;

            }

        }

      

        public void Dispose()

        {

            currentSession.Dispose();

        }

      

        public T UniqueResult<T>(IQuery query)

        {

            try

            {

                return query.UniqueResult<T>();

            }

            catch (Exception)

            {

                currentSession.Close();

                throw;

            }

        }

      

        public System.Collections.Generic.IList<T> ListResult<T>(IQuery query)

        {

            try

            {

                return query.List<T>();

            }

            catch (Exception)

            {

                currentSession.Close();

                throw;

            }

        }

      

        public System.Collections.Generic.IEnumerable<T> EnumerateResult<T>(IQuery query)

        {

            try

            {

                return query.Enumerable<T>();

            }

            catch (Exception)

            {

                currentSession.Close();

                throw;

            }

        }

      

    }

    When hitting an exception all this helper does is clean up after which it rethrows the exception, it's up to its user to take further action.

    All database interaction through nHibernate is now stuffed in this helper class. It can be used by a generic repository.

    public class Repository<T>

    {

        private readonly INhibernateHelper hibernate;

        private readonly string className;

      

        public Repository(INhibernateHelper hibernate)

        {

            className = typeof(T).Name;

            this.hibernate = hibernate;

        }

      

        public IQuery BuildQuery(string queryString)

        {

            return hibernate.Query(string.Format("from {0} where {1}", className, queryString));

        }

      

        public IList<T> ListAll(string orderBy)

        {

            string queryString = string.Format("from {0} order by {1}", className, orderBy);

            IQuery query = hibernate.Query(queryString);

            return hibernate.ListResult<T>(query);

        }

      

        public IEnumerable<T> EnumerateAll()

        {

            string queryString = string.Format("from {0}", className);

            IQuery query = hibernate.Query(queryString);

            return hibernate.EnumerateResult<T>(query);

        }

      

      

        public IEnumerable<T> EnumerateInPeriod(string propertyName, DateTime from, DateTime till)

        {

            if (from == DateTime.MinValue)

                from = new DateTime(1753, 1, 1);

            if (till == DateTime.MaxValue)

                till = new DateTime(9999, 12, 31);

            string queryString = string.Format("from {0} where {1} >= ? and  {1} < ?", className, propertyName);

            IQuery query = hibernate.Query(queryString);

            query.SetDateTime(0, from);

            query.SetDateTime(1, till);

            return hibernate.EnumerateResult<T>(query);

        }

      

        public T FindUnique(string propertyName, string propertyValue)

        {

            string queryString = string.Format("from {0} where {1}=?", className, propertyName);

            IQuery query = hibernate.Query(queryString);

            query.SetString(0, propertyValue);

            return hibernate.UniqueResult<T>(query);

        }

      

        public T FindUnique(string propertyName, long propertyValue)

        {

            string queryString = string.Format("from {0} where {1}=?", className, propertyName);

            IQuery query = hibernate.Query(queryString);

            query.SetInt64(0, propertyValue);