Showing posts with label NHibernate. Show all posts
Showing posts with label NHibernate. Show all posts

NHibernate 2.0 beta1 was release a couple of days ago, so I thought it was time to go through some more new stuff that has been added since version 1.2.  I found a new useful helper class named CritieraTransformer which can be used to clone ICritiera queries. This is very useful if you want to perform multiple queries with small variations (in the where clause for example). It also has a useful function that adds a row count projection to a query.

Example:

var customersCritiera = session.CreateCritiera(typeof(Customer));
var totalCustomersCritiera =  CriteriaTransformer.TransformToRowCount(customersCritiera);

var inGroupCriteria = 
  CriteriaTransformer.Clone(customersCritiera)
    .Add(Expression.Eq("Group", group));

var goldenInGroupCritiera = 
  CriteriaTransformer.Clone(inGroupCriteria)
    Add(Expression.Eq("IsGold", true);                          
                
IList results = session.CreateMultiCriteria()  
     .Add(inGroupCriteria)
     .Add(goldenInGroupCritiera)
     .Add(totalCustomersCritiera)
     .List();

IList inGroupCustomers = (IList)results[0];
IList customers = (IList)results[1];
IList counts = (IList)results[2];
int count = (int)counts[0]; 

The multi criteria feature allows you peform multiple database queries in a single database call, the downside is that the IMultiCritiera interface does not support generic lists.

There is a new framework in the NHibernate Contrib project named NHibernate.Validator. The project began as port of the java Hibernate.Validator project and is started by Dario Quintana. This framework allows you to validate objects in a similar way to other validation frameworks except that it has out of the box integration with the NHibernate's entity lifecycle. This means that you can configure it to do validation on entity insert/updates. The integration with NHibernate is not required however.

You can specify the validation rules either as property/field attributes directly in the code or in a separate xml file with a schema similar to that used in NHibernate mapping files.

Example:

public class User
{
  public virtual int Id
  {
      get { return id; }
  }

  [NotEmpty, NotNull]
  public virtual string UserName
  {
      get { return userName; }
      set { userName = value; }
  }

  [Email]
  public virtual string Email
  {
      get { return email; }
      set { email = value; }
  }

  [Past]
  public DateTime CreatedDate
  {
    get { return createdDate; }
    set { createdDate = value; }
  }

  [Min(18, Message="You are to young!")]
  public int Age
  {
    get { return age; }
    set { age = value; }
  }

  [CreditCardNumber]
  public string CreditCardNumber
  {
    get { return creditCardNumber; }
    set { creditCardNumber = value; }
  }
  
  ///... 
}

If you don't like to clutter your code with attributes you can use the xml config option, example:

<nhv-mapping xmlns="urn:nhibernate-validator-1.0">
  <class name="NHibernate.Validator.Demo.Winforms.Model.Customer, NHibernate.Validator.Demo.Winforms">    
    <property name="FirstName">
      <not-empty/>
      <not-null/>
    </property>    
   
    <property name="Email">
      <email/>
    </property>

    <property name="Zip">
      <pattern  regex="^[A-Z0-9-]+$" message="Examples of valid matches: 234G-34DA | 3432-DF23"/>
      <pattern  regex="^....-....$" message="Must match ....-...."/>
    </property>    
    
  </class>  
</nhv-mapping>

Personally I can barley stand the NHibernate xml mapping files (don't like to poke around in xml files that much) so I think I prefer the attribute version. But it is nice to have this option. It makes it possible to validate objects in third party assemblies that you do not have the code for. There are many more validators than the ones used above and it is very easy to create custom validators.

You can configure the validation engine in code or in app/web.config, this is how you can do it in code:

NHVConfiguration nhvc = new NHVConfiguration();
nhvc.Properties[Environment.ApplyToDDL] = "false";
nhvc.Properties[Environment.AutoregisterListeners] = "true";
nhvc.Properties[Environment.ValidatorMode] = "UseAttribute";
nhvc.Mappings.Add(new MappingConfiguration("NHibernate.ValidatorDemo.Model", null));

ValidatorEngine validator = new ValidatorEngine();
validator.Configure(nhvc);

Since NHibernate.Validator uses the event listener system I think you have to use NHibernate 2.0 if you want the NHibernate integration. To validate an object you simply use the Validate function, here is a simple example (using MonoRail):

public void Create([DataBind("user")] User user)
{
  InvalidValue[] errors = validator.Validate(user);

  if (errors.Length > 0)
  {
    Flash["errors"] = errors;
    RedirectToAction("index");
  }
  else
  {
    repository.Create(user);
  }
}

And here is the view:

<div>
    <h2>Create user</h2>    
    
    ${Html.FormToAttributed("Home", "Create", {@id: "create-form"})}
    
    <p>    
        <label for="UserName">UserName:</label>
        ${Form.TextField("user.UserName")}
        
        <label for="UserName">Email:</label>
        ${Form.TextField("user.Email")}
        
        ${Html.SubmitButton("Submit")}
    </p>
            
    ${Html.EndForm()}
    
    
    <?brail if IsDefined("errors"): ?>
        <ul>
        <?brail for error in errors: ?>
            <li>${error.PropertyName}: ${error.Message}</li>    
        <?brail end ?>
        </ul> 
    <?brail end ?>
</div>

This is of course a very simple example. You probably want to have the error message after each field and some client based validation. I think I will do another post about trying to integrate NHiberante Validator with JQuery validation.

If you want to try NHibernate validator and do not want to build it from the trunk there is a 1.0 alpha release available on sourceforge. The release contains a WinForms examples that shows how to integrate it with the WinForms error provider system.

Yesterday I held a short seminar (2 hours) on Open Source and .NET for the Systems Development team at Cybercom Sweden East. The seminar was split into three separate presentations, I will try to give a short summery of them here. At the end of the post I will post links to the powerpoints and application examples.

Open Source and .NET 

This presentation covered a short introduction to open source. I began with explaining the most common licences (GPL, LGPL, Apache) and then moved on to list a few interesting framework and development tools. But mostly it was about why I think utilizing open source is something that we as .NET developers need to be better at, and why this will be very important if the .NET platform is going to stay competitive.

I have never worked professionally as a java developer but my understanding is that tools like Eclipse and frameworks like Struts, Hibernate and Spring are used to a very a large extent (30 - 70% according to some studies). And what types of platforms do java applications run on? They usually run on an open source OS and use an open source web server (Apache) or application server. This means that the devolvement environment, tools and frameworks are largely based on open source software.

I think this fact contributes to the mindset of java developers and project managers to actively search for, and be more open to, open source solutions. I feel that many .NET developers are prone to constantly reinvent the wheel, for example by creating their own logging framework or a basic data layer tool without ever searching for existing alternatives, be that open source or commercial.

Open Source benefits

I also talked about some of the benefits I see with open source frameworks compared to Microsoft's offerings. One of the main things I mentioned here was innovation, I think that a lot of innovation in development methodologies (TDD), design, frameworks and tools are coming to large extent from the open source community. The fact that open source software starts without commercial aspirations or requirements results in software that is more focused on solving real problems and less on flashy designers.

Open Source problems

The major problem I see with open source is the lack of commercial support services. I don't see this personally as a problem but as a problem when trying to sell open source solutions to management. There are many companies that are offering training and support for open source frameworks and tools on the java side but very few for the .NET equivalents. I think this point is also one of the major reasons why .NET  is so behind java when it comes to open source adoption. The lack of commercial support is something I partly blame on Microsoft who instead of promoting and supporting open source actively compete with it.

Open Source trends

I ended the presentation by showing some statistics from the IOUG Open Source 07 Report. This report really shows how much open source software is currently being used by big enterprise companies (almost exclusive non .NET software) and that this is an increasing trend. Just between 2006 and 2007 the increase in the use of open source software was 26%. The report also showed the reasons why open source software is being used. The two main reasons were cost savings and no proprietary vendor lock-in.

Not to be misunderstood, I am not an open source fundamentalist, I just think there is a lot of value in some open source frameworks and tools and I think .NET developers in general (maybe not those who happen to read this blog) should utilize this resource more. 

Log4Net & NHibernate

I also held a presentation about Log4Net and an hour long presentation about object-relational mapping with NHibernate which included a short live coding demo. 

Here are the powerpoints (they are in Swedish):

I also made some sample applications:

I wanted some code in this post so here is snippet from the NHibernateDemo application that shows how simple property projection is with the NHibernate Critiera API:

public IList<string> GetAllBlogOwnerNames()
{
  return Session.CreateCriteria(typeof(User))
    .Add(Expression.IsNotEmpty("Blogs"))
    .SetProjection(Projections.Property("UserName"))
    .List<string>();
}

One of the biggest strengths of O/R mappers is that many have object-oriented "query by criteria" API. I will show what I mean by that in a bit. But to explain why I think a criteria API is such a great thing I will show the alternatives first.

Lets take a common search form scenario where a user can specify a number of customer filtering options like date added, name, the customer should have an address, the customer should be linked to a specific salesman, etc. If you were forced to use a stored procedure how would you implement this query?

I have seen a couple of solutions to problems like this, here is one that is really bad:

IF @name = ''
BEGIN 
     --- the whole query for this case 
END    
ELSE IF @name <> '' AND @shouldHaveAddress IS NOT NULL 
BEGIN 
    --- the whole query for this case 
END 
ELSE IF @name <> '' AND @shouldHaveAddress IS NOT NULL AND @salesmanNr <> '' 
    --- the whole query for this case 
END

Here the whole query is duplicated for each possible parameter mutation. I have seen a stored procedure like this recently that duplicated a very long query about 10 times (with very small variations in the where and join clauses).

Another solution is to complicate the query with embedded IFs, CASE and additional OR statements. But this solution does not only make the query unintelligible but also I think has some limitations. The solution that I see many arrive at is to build the query using string concatenation.

SET @sqlSelect = 'SELECT distinct ' + @NEWLINE + ' ' + @returnColumns + @NEWLINE
SET @sqlFrom = ' FROM Customers cust' + @NEWLINE
IF @companies is NOT NULL
BEGIN
  SET @sqlFROM = @sqlFROM + ' JOIN Companies comp on comp.Id=cust.CompanyId' + @NEWLINE
  SET @sqlFROM = @sqlFROM + ' LEFT JOIN Addresses addr on addr.Id=cust.AddressId ' + @NEWLINE  
END
IF @salesmanId IS NOT NULL
BEGIN
  SET @sqlFROM = @sqlFROM + ' JOIN Salesmen sal on sal.Id=' + @salesmanId 
END
...
..
.

I actually think that building up the query like this is not all that bad, however I would do it in C# and skip the stored procedure. The reason I prefer this approach is that it there is less duplication and because it is somewhat easier to maintain. But it is far from what we want!

So how do can we handle this via the nhibernate query api?

ICriteria query = session.CreateCriteria(typeof(Employee));

if (searchOptions.FirstName != null)
{
  query.Add(Expression.Eq("FirstName", searchOptions.FirstName));
}

if (!searchOptions.LastName != null)
{
  query.Add(Expression.Eq("LastName", searchOptions.LastName));
}

if (searchOptions.PhoneNumber != null)
{
  query.CreateCriteria("PhoneNumbers")
    .Add(Expression.Like("Number", searchOptions.PhoneNumber + "%"));
}
return query.List<Employee>();

The nhibernate criteria api might be verbose for simple scenarios compared to a SQL query in a string, but it is scenarios like the above that it really shines :) But wait it can be better. If you use Ayende's great NHibernate Query Generator (NHQ) you can do this:

QueryBuilder<Employee> query = new QueryBuilder<Employee>();

if (options.FirstName != null)
{
  query &= Where.Employee.FirstName == options.FirstName;
}

if (options.LastName != null)
{
  query &= Where.Employee.LastName == options.LastName;
}

if (options.PhoneNumber != null)
{
  query &= Where.Employee.PhoneNumbers.Number.Like(options.PhoneNumber, MatchMode.Start);
}            

return Repository<Employee>.FindAll(query, OrderBy.Employee.LastName.Desc);

NHQ is a very clever code-gen util that you setup as a post-build step. It generates the Where/QueryBuilder classes from the nhibernate mapping files. The result is that you do not need any strings in your queries! More commonly you use it like this:

return Repository<User>.FindAll(Where.User.Name == name);

I think it comes very close to using LINQ. So to end this post I guess I need to show how the above query would look with LINQ, because LINQ to SQL handles the above scenario pretty well.

IQueryable<Employee> query = linqContext.Employees;

if (options.FirstName != null)
{
  query = query.Where(emp => emp.FirstName == options.FirstName);
}

if (options.LastName != null)
{
  query = employees.Where(emp => emp.LastName == options.LastName);
}

if (options.PhoneNumber != null)
{
  query = from emp in query
	  from phoneNr in emp.PhoneNumbers
	  where phoneNr.Number.StartsWith(options.PhoneNumber)
	  select emp;
}            

return employees.ToList();

The above code is nice, but I think querying across relations is handled nicer in the nhibernate critiera api especially when using NHQ. Well that is all, now you know why I think a criteria API is are one of the mayor reasons to use an O/R mapper.

The new statistics class in Hibernate 2.0 is a great tool to use for monitoring potential performance problems with your app. The class exposes a large number of counters and measurements. Here are some highlights of what is available:

  • EntityDeleteCount
  • EntityInsertCount
  • EntityLoadCount
  • EntityUpdateCount
  • QueryExecutionCount
  • QueryExecutionMaxTime
  • QueryExecutionMaxTimeQueryString
  • QueryCacheHitCount
  • ConnectCount
  • SessionCloseCount
  • SessionOpenCount
  • CollectionLoadCount
  • CollectionUpdateCount
  • CollectionRemoveCount
  • Queries
  • PrepareStatementCount

The statistics engine can be turned on/off dynamically with the IsStatisticsEnabled property and you can get statistics on specific entities as well.

Just to try this out I created a MonoRail filter that checks for "nhibstats" in the query parameters of the request. If the parameter is found it will turn on the nhibernate statistics, this is done before the controller action is executed. After the action as completed it will add the stats data to the PropertyBag so the view can access it.

public class NHibernateStatsFilter : IFilter
{
    public bool Perform(ExecuteWhen exec, IEngineContext context, IController controller,
                        IControllerContext controllerContext)
    {
        if (context.Request["nhibstats"] == null)
            return; 
        
        if (exec == ExecuteWhen.BeforeAction)
        {
            sessionFactory.Statistics.Clear();
            sessionFactory.Statistics.IsStatisticsEnabled = true;
        }
        else if (exec == ExecuteWhen.AfterAction)
        {
            controllerContext.PropertyBag["nhibernate_stats"] = sessionFactory.Statistics;
            sessionFactory.Statistics.IsStatisticsEnabled = false;
        }
    }
}

I use the same filter for both the before and after action "events", this means that you have to specify the filter attribute like this:
[Filter(ExecuteWhen.BeforeAction | ExecuteWhen.AfterAction, typeof(NHibernateStatsFilter))]
public class BaseController : Controller
{
        
}
Now you can add to your top layout view something like this:
<?brail if IsDefined("nhibernate_stats"): ?>
    <dl>
        <dt>EntityInsertCount</dt>
        <dd>${nhibernate_stats.EntityInsertCount}</dd>        
        <dt>EntityUpdateCount</dt>
        <dd>${nhibernate_stats.EntityUpdateCount}</dd>        
        .
        ..
        ...
    </dl>
<?brail end ?>

I think this could be really useful. Now you don't have to open SQL Profiler whenever you want to know what NHibernate is up to!

NHibernate 2.0 Alpha1 was released a few days ago and the 2.0 version brings a lot of new features. There is a completly new event / listener system that can be used for all sorts of cross-cutting concerns. A basic example would be to register a save/update listener that would update some common fields (like ModifiedBy, ModifiedDate).

In order to use the event system you need to create a class that either inherits from a default nhibernate event listener or from the many event interfaces. Here is an example:

using NHibernate.Event;
using NHibernate.Event.Default;

public class CustomSaveEventListener : DefaultSaveEventListener
{
    protected override object PerformSaveOrUpdate(SaveOrUpdateEvent evt)
    {
        IEntity entity = evt.Entity as IEntity;
        if (entity != null)
            ProcessEntityBeforeInsert(entity);

        return base.PerformSaveOrUpdate(evt);
    } 

    internal virtual void ProcessEntityBeforeInsert(IEntity entity)
    {
        User user = (User) Thread.CurrentPrincipal;
        entity.CreatedBy = user.UserName;
        entity.ModifiedBy = user.UserName;
        entity.CreatedDate = DateTime.Now;
        entity.ModifiedDate = DateTime.Now;
    }
}

The reason I inherit from the default implementation is that when you specify a listener in the configuration you will replace the default listener. I am not sure what the recommended way to this is but the way I understand it is that you can choose two ways, iether you inherit a default implementation and only specify your listener in the configuration or you just implement the event interface(ISaveOrUpdateEventListener for example) but then you also need to specify the default implementation in the configuration (in order not to loose functionality).

Here is how the configuration looks like:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
        ...
        <listener class="NHibTest.Listeners.CustomSaveEventListener, NHibTest" type="save" />
        <listener class="NHibTest.Listeners.CustomSaveEventListener, NHibTest" type="save-update" />                    
    </session-factory>
</hibernate-configuration>

You can also place the listeners within a event xml element if you want to setup many listeners of the same type. It is also possible to do this via code like this:

Configuration cfg = new Configuration();
cfg.EventListeners.SaveEventListeners = 
    new ISaveOrUpdateEventListener[] {new CustomSaveEventListener() };

There are many other event types, for example Load, PreUpdate, DirtyCheck, Autoflush, PostDelete. These events could be used in interesting scenarios, for example validation and security.