Override interface mappings and creata a generic entity version filter

by Tom 20. April 2010 15:02

Introduction

For one of my customers I needed to have some kind of versioning for a whole bunch of entities on my database. Since I use my very own MvcExtensions framework, I wanted to include a functionality which would automatically filter all entities based on this interface :


    public interface IVersionAware
    {
        string Version { get; set; }
    }

In short, I only want to get the entities of the current version through my repository. This interface would then automaticly imply that all data could be filtered by setting a version filter.

I took me quite some time, but spending a weekend at the Dutch coast cleared my mind a bit, and after the weekend I managed to get it working...

The void (tm)

 

Hit the road, Jack !!

Ok, so how can we do this ?

In MvcExtensions I map my domain classes to my database in the following way :


    public class MyDomainDefinition: IDomainDefinition
    {
        public MyDomainDefinition() { }

        public Assembly DomainAssembly
        {
            get { return typeof(Model.Kit).Assembly; }
        }

        public DomainType GetDomainType(Type t)
        {
            if (t.Namespace==typeof(Model.Kit).Namespace)
                return DomainType.Class;
            else
                return DomainType.None;
        }

        //if !=null write mapping files to disk
        public string WriteHbmFilesToPath
        {
            //get { return @"c:\tmp"; }
            get { return null; }
        }
    }

This might look quite simple, but it is an extensive abstraction layer over fluent nhibernate which takes away most of the complexity, and adds a lot of functionality (bitmap storage, multilingual fields to name a few).
After looking around for some info on the net about filtering using fluent nhbernate, I found a solution: one could define a system-wide filter using the following Filterdefinition and mapping.ApplyFilter :


    public class VersionFilter : FilterDefinition
    {
        public static readonly string FILTERNAME = "MyVersionFilter";
        public static readonly string COLUMNNAME = "Version";
        public static readonly string CONDITION = COLUMNNAME + " = :" + COLUMNNAME;

        public VersionFilter()
        {
            WithName(FILTERNAME)
              .WithCondition(CONDITION)
              .AddParameter(COLUMNNAME, NHibernateUtil.String);
        }

        public static void Enable(NHibernate.ISession session, string version)
        {
            session.EnableFilter(FILTERNAME).SetParameter(COLUMNNAME, version);
        }

        public static void Disable(NHibernate.ISession session)
        {
            session.DisableFilter(FILTERNAME);
        }
    }

And this would be the code to map it for some class.


automapping.Override<SomeClassImplementingIVersionAware>(
  mapping=>
  {
    mapping.Id(x=>x.Id);
    mapping.Map(x=>x.Version).Column(VersionFilter.COLUMNAME);
    mapping.ApplyFilter<VersionFilter>();
  }

Since I do not want to call this override for each class implementing IVersionAware, I decided to create a workaround. I spent quite some time in trying to implement this, until I noticed why my workaround was not working: there was a (small bug) in the fluentnhibernate framework.
So I forked fluentnhibernate, fixed the bug, and sent a pull request to the fluentnhibernate guys, and Paul Batum reported to me that my bugfix will be integrated into the next merge, together with some unit tests. For now, you can get the fixed sourcecode from my github version.

... And don't you come back no more....

So, after fixing this, I could get to work again. Since I first tried using IAlterations and Overrides for fluent nhibernate, but all were failing due to the bug, I finally got to this code (which worked after I fixed the bug in fluent nhibernate):


    public static class AutoPersistenceModelExtensions
    {
        public static AutoPersistenceModel OverrideInterface<I,C>(this AutoPersistenceModel model
            , IEnumerable<Type> MyTypes)
            where C:IInterfaceMap<I>,new()
        {
            var modeloverride = model.GetType().GetMethod("Override");
            var interfacemap = new C();
            var cm = typeof(C).GetMethod("Map");
            foreach (var t in MyTypes.Where(x => typeof(I).IsAssignableFrom(x)))
            {
                var act = cm.MakeGenericMethod(t).Invoke(interfacemap,null);
                modeloverride.MakeGenericMethod(t).Invoke(model, new object[] { act });
            }
            return model;
        }
    }

    public interface IInterfaceMap<I>
    {
        Action<AutoMapping<T>> Map<T>() where T:I;
    }

This extension method allows you to override the mappings for interface fields in a very simple way; here is the example for the IVersionAware interface:


    public class VersionAwareInterfaceMap : IInterfaceMap<IVersionAware>
    {
        public Action<AutoMapping<T>> Map<T>() where T : IVersionAware
        {
            return mapping =>
                {
                    mapping.Map(x => x.Version).Column(VersionFilter.COLUMNNAME);
                    mapping.ApplyFilter<VersionFilter>();
                };
        }
    }

And in the MvcExtensions database bootstrapper, I would call this :


        protected Database(IPersistenceConfigurer pcfg, IDomainDefinition mappings)
        {
             // some stuff deleted because it is not relevant here
            var cfg = Fluently.Configure()
                .Database(pcfg)
                .Mappings(m => {
                    var am1 = AutoMap.Assembly(mappings.DomainAssembly)
                        .Where(t => clsmaps.Contains(mappings.GetDomainType(t)))
                        // some stuff deleted because it is not relevant here
                        );
                    var types = mappings.DomainAssembly.GetTypes().Where(x =>
                                typeof(IVersionAware).IsAssignableFrom(x) &&
                                mappings.GetDomainType(x) != DomainType.None);
                    if (types.Count()>0)
                    {
                        am1.OverrideInterface<IVersionAware,VersionAwareInterfaceMap>(types);
                        am1.Add(new VersionFilter());
                    }
                        // some stuff deleted because it is not relevant here

                })
                .BuildConfiguration();
            // some stuff deleted because it is not relevant here
        }

... No more ....

In order to filter my data I would call this :


VersionFilter.Enable(sUnitOfWork.Session,"v1.3.2");

And disabling it again goes like this :


VersionFilter.Disable(sUnitOfWork.Session);

That's all there is to it; all entities implementing the IVersionAware interface will be automatically filtered if you do set the filter....

For a full version you can check out the sourceode over at github.

If you have any questions or remarks, do not hesitate to post them...

Enjoy

Bookmark and Share

Tags: , , , , , , ,

CodeProject | Development | Howto | News

"Var keyword is for JavaScript" - about using the var keyword & other coding guidelines

by Tom 31. March 2010 04:28

Introduction

Today I was reading an article on Codeproject, and I was really astounded by the way some people rate articles and give comments...

It was an article about someone who had implemented a simple service locator which contained the following code sample :


using System;
using CuttingEdge.ServiceLocation;
using Microsoft.Practices.ServiceLocation;

public class Global : System.Web.HttpApplication
{
  protected void Application_Start(object sender, EventArgs e)
  {
     // 1. Create a new Simple Service Locator container
     var container = new SimpleServiceLocator();

     // 2. Configure the container

     // Register a delegate that will create a new
     // instance on each call to GetInstance.
     container.Register<ISamurai(() =>
     {
        var weapon = ServiceLocator.Current .GetInstance();
        return new Samurai(weapon);
      });

      // Register a single object instance that always
      // be returned (must be thread-safe).
      container.RegisterSingle(new Katana());

      // 3. Register the container to the Common Locator
      ServiceLocator.SetLocatorProvider(() => container);
    }
}

Which seems quite obvious to me. Since I noticed a comment titled 'my vote of 2', I was curious why this article would be voted such a low score (2 out of 5). I checked the comment and I was astounded:

Please note: the keyword "var" is supposed to be used with anonymous types. You should not use it for anything else. Otherweise please start
programming java script

Who cares ?

Actually, I do.

Since I could not resist I posted the following comment:

Ahum... there have been numerous issues about this, but in general it should not pose a problem, because it is quite clear what it's intentions are at the beginning; i.e. :

var sl = new SimpleServiceLocator();



Is not really more obvious then :

SimpleServiceLocator sl = new SimpleServiceLocator();



In fact, the information in there is the same, but the second one is more verbose, so every person in his right mind would opt for the first alternative.
This might be different if you use a function which does not directly expose the return type in the function name; i.e. :

var x = SomeFunction(y,z);



This is considered bad practice by most.

This one is not :

var myservice = sl.Resolve<IMyService>();



Because the initialization contains enough obvious info to give pointers to the var's type.

So, if this is the only reason why you are giving a 2 (the author has obviously invested quite some time in this article), then you might need to start doing some JavaScript yourself

 

After tweeting about this, I had an interesting conversation with @JacoPretorious about this, who says he uses var everywhere, but pays more attention to variable names.

While I understand what he means, IMHO variable names should not infer the type, only the meaning of the content if necessary.

I personally think there is nothing wrong with using single letters as variable names, as long as the intent is obvious. This is an example that is perfectly valid imho :


public bool InvalidateCustomer(int CustomerId)
{
  var c = sRepo.GetById<Customer>(CustomerId);
  if ( c.Orders.Where(o=>o.PaymentReceivedOn==null).Any())
    return false;
  c.Valid=false;
  sRepo.SaveOrUpdate(c);
  sUOW.Commit();
  return true;
}

This one is not IMO :


public class MyProcessQueue
{
  public void ProcessQueue()
  {

    for(;;)
    {
       var p = Queue.Next();
       if (p==null)
         break;
       sProcessor.Process(p);
    }
  }
}

Since you can not infer the type from Queue, you should make the type explicit :


public class MyProcessQueue
{

  public void ProcessQueue()
  {

    for(;;)
    {
       Order o = Queue.Next();
       if (o==null)
         break;
       sProcessor.Process(o);
    }
  }
}


This would change if the MyProcessQueue would be a generic class :


public class MyProcessQueue<T> where T:ISomeInterface
{
  public void ProcessQueue()
  {

    for(;;)
    {
       var p = Queue.Next();
       if (p==null)
         break;
       sService.Process(p);
    }
  }
}



In this case, I think you have enough information available to know that the type should be about the generic class. Using more explicit names for the variables does not add a lot info for me; I do not find the following (exagerated) example more abvious than the previous one; in fact, it takes more time to get the intent here, because your mind needs to process more information (also note the comments, which do not provide any extra info to me) :


public class MyProcessQueue<T>
  where T:ISomeInterface

  // Process all jobs in the queue, until there is nothing left  
  public void ProcessAllISomeInterfacesInTheQueue()
  {
    // loop forever
    for(;;)
    {
       // get the next instance to process from the queue; 
       // if it returns null there are no more processes left on the queue 
       ISomeInterface TheNextISomeInterfaceInstanceToProcess = Queue.Next();

       if (TheNextISomeInterfaceInstanceToProcess==null)
       {
          //exit the infinite loop 
         break;
        }
       // process it 
       sServiceThatProcessesSomeInterfaceInstance
          .Process(TheNextISomeInterfaceInstanceToProcess);
       // go to the next one
    }
   // return 
  }
}

There is way too much info here which can all be easily derived from the code, and if you change the code and forget the comments, this might actually do the opposite: cause confusion.

In conclusion

While this is all about preference and highly dependent on you point of view and background, I do think that the approach I am personnaly using is one of the better ones. They offer all the amount of information that you could need with the minimum amount of code.

If you do have another opinion, do not hesitate to let me know...

 

Bookmark and Share

Tags: , , ,

CodeProject | Development | Howto | News

Screencast: Build an Asp.net MVC application quickly using MVCExtensions

by Tom 29. January 2010 20:16

Introduction

This is my first screencast for my MVCExtensions project, it shows you how to get started and build a simple tasklist.

PS: This is the direct link to the powerpoint used:
http://docs.google.com/present/view?id=dgt3mk3c_6fmhrd9c5

Some background info

This was my first screencast, and it took me about 7 attempts to finally get it to a point where it was more or less acceptable. For my sixth and seventh attempt I finally found some good screencap software : BBFlashback Express.

Anyway, this has been an interesting experience, and now enjoy mvcextensions !!!

More...

Tags: , , , , ,

CodeProject | Development | Howto | News

The advantage of using BDD over TDD

by Tom 26. January 2010 13:48

Introduction

After reading the latest post from @jeremydmiller I felt the urge to write a small article about the BDD part since there might be missing a vital part here about BDD...

More...

Tags: , , , , , , ,

CodeProject | Development | News

Build asp.net MVC applications FAST with MVCExtensions v0.4

by Tom 20. January 2010 19:28

Introduction

Today I finished v0.4 of my MVCExtensions library and I pushed the sourcecode to github.

I also included a very simple tasklist, in order to show you on how to get started using this library. You can also see (slightly outdated) example code in this blog post...

You can see a demo of the tasklist app running here. (Try entering a task without a name, or with a name that has more then 256 chars to see the custom strings in action).

You can download the full sourcecode here.

Update

I now made a screencast as well. it is available here.

More...

Tags: , , , , , , , , , , ,

CodeProject | Development | News

Teaser on my upcoming mvcextensions project release

by Tom 18. January 2010 15:51

Hi there,

I am going to give you a quick teaser on how to setup a full asp.net mvc application with database & all the rest using my soon-to-be-updated MVCExtensions library.

More...

Tags: , , , , , , , ,

CodeProject | Development | News

Einstein's theories explained in 5 minutes: (special) relativity

by Tom 14. January 2010 15:36

Introduction

In the past I have noticed a lot of people talk about (special) relativity and other physics theories, but when you ask them a few questions, they do not seem to grasp the concept....

In this series of blog posts I will try to explain you some of his concepts the way I understand them...

The inspiration for this series has been one of Einstein's quotes :

"Make everything as simple as possible, but not simpler"

I am no physicist by any means, nor a good mathematician, so you should never ask me any questions about the proof or maths about something, since I simply do not know. If you ask most people about these theories they usually start making it way too complicated for one of the two following reasons :

  • They do not understand it, so they try to blow you away with complicated things they heard about it, so you would stop asking questions about it...
  • They do understand it, but their explanation assumes you know the "language of physicists" - which you do not - so it seems like they are talking Jibberish all the way...

We will start with a very popular concept : the theory of special relativity.

More...

Tags: ,

News | Science | Tom's blog

2009 retrospective: .Net technologies and lessons learned

by Tom 2. January 2010 03:02

my pride & joy

Introduction

 

In December 2008 I was doing my job as a freelance technical analyst for a big company. While it was a very interesting job in several ways, I felt that a burn-out was coming up. I had no idea whether this was due to the job, or due to my personal merits ( a newborn and a one-year old son, lots of tasks and chores on my to-do list for our house, a busy social life, ...) Instead of waiting for the man with the hammer, I decided to be proactive about it, so I decided to quit the job and reinvent myself during 2009.

It has been both an interesting, very challenging and enriching year for me, with both high peaks and low valleys.

I decided to write this blog post in order to evaluate myself, and I am hoping that other people might find some inspiration in this as well.

 

 

 

 

 

More...

Civilian's manifest against a ridiculous tax : we now need to pay extra taxes on usb-sticks/external hard discs because we MIGHT copy music/video on it

by Tom 30. December 2009 03:34

Introduction : "Oh my God"

The Belgian government managed to do it again; starting from February we have to pay taxes on portable storage, because we MIGHT copy some music on it.

This is utter failure in the biggest possible way; I can accept that our dear Minister Q. has had some really strange track records, but this is really his 'best' realisation ever !!!

As you might or might not know, similar to other countries, we already have to pay a certain amount of taxes for blank DVD's/CD's. In my personal opinion this was really ridiculous, but since I use about 1 CD/DVD per month, I never really bothered...

I assume that people probably stopped buying DVD's/CD's, and as a compensation our government needed to find an alternative. And now they found it !!

Here is an English (google translated) excerpt from an article on tweakers.net about it :

Thus, as from February 1 for an iPod Touch with 64GB of flash storage paid 3 euros extra. A set-top box with a 500GB hard drive is responsible for 10.75 euros, while an external hard drive 1TB or larger to yield 9 Euro. 
Also, a distinction is made between different types of storage devices with the same: an MP3 player with 16GB flash memory has a Auvibel fee of 3 Euro, while a USB stick with an identical capacity to 1.35 Euro copying levy to be paid.

More...

Tags: ,

News | Tom's blog

Howto+why using a prototype & bdd for a project estimate + personal rant

by Tom 22. December 2009 13:57

Introduction

As you might or might not now, estimating the budget for a project can be very hard sometimes. In order to get started on a project we first need a real estimate of what the client will need, and the client should know what I am going to deliver to him/her.
What I personally learned from the past is that one can never be fine-grained enough, since there will always be mismatches somewhere.

We can however try to offer the client something that he/she can both understand and work with, next to a description of what everything should do (from a business point of view).

How can we do this, while investing as little work as possible ?

 

Unfortunately one can not correctly estimate projects without doing some work

As straightforward as this might seem, most people do not seem to be able to grasp this ( do not be ashamed; I have been guilty as well ).

In order to give a correct estimate, you have to INVEST a decent amount of TIME.

More...

Tags: , , , , ,

CodeProject | Development | Howto | News | Tom's blog

About me

Tom Janssens op LinkedIn

Tom Janssens op twitter

Core bvba RSS

My name is Tom Janssens and I am the owner of Core bvba, a software and consultancy company.
I am married to Liesbeth and have 2 sons named Quinten and Matisse.
ICT is both my job and passion.
Next to this my other hobby is actively playing music (mostly guitar).

More info about me and my company...

Recent Comments