var blog = new ThoughtStream(me); RSS 2.0
 Wednesday, November 26, 2008

In the comments of my previous post - Descriptive State Enumeration - Maxim Tihobrazov asked me to show how to map a state pattern with NHibernate; and I am more than happy to oblige!

NHibernate Mapping Options

I certainly don't claim to be an expert on NHibernate, but I do use it on a daily basis and I've solved my fair share of problems - including how to map a State pattern with NHibernate. According the NHibernate inheritance documentation, there are three core ways of mapping this pattern:

  1. Table per class hierarchy (I've always called it "record per class") - each subclass (state instance, in this case) is associated with a specific record in a table. All of the subclasses are found in the same table.
  2. Table per subclass (also called a "joined sub class") - each sub class has it's own table and is joined to the super class by a one to one relationship with it's primary key.
  3. Table per concrete class - each sub class has it's own table and is mapped by the specific class type, not by the abstraction.

My Choice - Table Per Class Hierarchy

In my current set of applications, I've always used the table per class hierarchy option so that is what I will describe here. My reasons for choosing this option are simplicity in the mapping and more importantly - not having a need to store the records in their own tables. Each of my states can be very cleanly represented as a record in my state table.

Setting Up Shop

Let's consider the same coffee shop that I've used in both of my PTOM posts - in this case, we're dealing specifically with the Order class and it's OrderStatus state. It's necessary to note that when I am working with NHibernate and the state pattern, I actually do set up my state models a little different. First off - we need an Id for NHibernate to map to the table's primary key. Secondly, I like to keep the core information in the abstract base class and provide all the varying values via a constructor. Third, each of the inheriting classes needs to provide a default (no args) constructor. Forth, we need a way for NHibernate to know which class it should actually instantiate, when loading - a "descriminator". I like to use a simple string Name property for this. And lastly - I think (though I am likely wrong on this aspect) that the abstract base class needs to provide a default constructor. Fortunately, the constructors we need don't need to be public - they can be private.

With all of that being said, here is realistic code base that I would use for my Order and OrderStatus model:

public class Order
{
   public int Id { get; set; }
   public OrderStatus Status { get; set; }
}
 
public abstract class OrderStatus
{
   public static InProcess = new InProcessStatus();
   public static Totaled = new TotaledStatus();
   public static Tendered = new TenderedStatus();
   public static Delivered = new DeliveredStatus();
 
   public int Id { get; set; }
   public bool DisplayForFullfillment { get; }
   public string Name { get; set; }
 
   private OrderStatus() { }
 
   private OrderStatus(int id, bool display, string name)
   {
       Id = id;
       DisplayForFullfillment = display;
       Name = name;
   }
}
 
public class InProcessStatus: OrderStatus
{
   private InProcessStatus(): base(1, false, "InProcess");
}
 
public class TotaledStatus: OrderStatus
{
   private TotaledStatus(): base(2, true, "Totaled");
}
 
public class TenderedStatus: OrderStatus
{
   private TenderedStatus(): base(3, true, "Tendered");
}
 
public class DeliveredStatus: OrderStatus
{
   private DeliveredStatus(): base(4, false, "Delivered");
}

The Fluent NHibernate Maps

I'm a huge fan of Fluent NHibernate. I've been using it since just after it was branched from the original ShadeTree code. And at one point, I had submitted so many patches that I was made a comitter on the project. So, it should be no surprise to anyone that I'm going to advocate using FluentNHibernate over the .hbm.xml mapping files. Truth be told, I don't even remember how to do the needed descriminators in hbm.xml files. There was some trick to the descriminator being the first specified items after the Id or something... it's just easier to do in FluentNHibernate, so I don't bother with hbm.xml files anymore.

The Order map is going to be as standard as any other map. You don't need to do anything special here. Just map the Id of the Order and the referenced OrderStatus. (I like to add a "CreateMap()" method that is called from the constructor, so that I can avoid the "virtual method call from a constructor" warning. But I also use the "treat warnings as errors" option for my C# projects).

public class OrderMap: ClassMap<Order>
{
   public OrderMap()
   {
       CreateMap();
   }
 
   public void CreateMap()
   {
       DefaultAccess.AsProperty();
       WithTable("Orders");
       Id(o => o.Id).GeneratedBy.Assigned();
   }
}

It's really the OrderStatus map that is special in this case. This is where we get into the details of the descriminator - telling NHibernate which specific instance to create, when loading the data from the database. In our case, we have added a "Name" field to our OrderStatus object and we will be explicitly using this property as the descriminator.

public class OrderStatusMap: ClassMap<OrderStatus>
{
   public OrderStatusMap()
   {
       CreateMap();
   }
 
   public void CreateMap()
   {
       DefaultAccess.AsProperty();
       WithTable("OrderStates");
       Id(s => s.Id).GeneratedBy.Assigned();
 
       DiscriminateSubClassesOnColumn<string>("Name")
 
           .SubClass<InProcessStatus>()
               .IsIdentifiedBy(OrderStatus.InProcess.Name)
               .MapSubClassColumns(x => { })
 
           .SubClass<TotaledStatus>()
               .IsIdentifiedBy(OrderStatus.Totaled.Name)
               .MapSubClassColumns(x => { })
 
           .SubClass<TenderedStatus>()
               .IsIdentifiedBy(OrderStatus.Tendered.Name)
               .MapSubClassColumns(x => { })
 
           .SubClass<DeliveredStatus>()
               .IsIdentifiedBy(OrderStatus.Delivered.Name)
               .MapSubClassColumns(x => { })
 
       Map(s => s.Name);    
   }
}

The key to all of this is the DescriminateSubClassesOnColumn method. The generics <string> tells us what .NET Type is being used to identify the specific class instances that we are dealing with and the ("Name") parameter is the column name in the database that represents the specific instance.

Then, we have the specific class instances referenced by the ".Subclass<type>" calls. This is a fluent interface, so ".Subclass" is a method that gets called directly off the DescriminatoeSubClassesOnColumn method. The specific type we want NHibernate to know about is specified in the generics parameter: ".SubClass<InProcessStatus>". The "IsIdentifiedBy" is where we give NHibernate the knowledge of what value in the "Name" column maps to what specific class in our code. To prevent magic string syndrome from setting in, I like to use the actual enumeration pattern of my OrderStatus to specify the string name of the class.

And finally, we have to provide an ugly workaround for our maps via the "MapSubclassColumns" method. There is an implementation issue in FluentNHibernate currently, and because of this issue we are forced to call the "MapSubclassColumns" method, with an empty lambda expression. If we don't call this method, the sub class will not get registered and NHibernate will not know how to handle the data in question. (I am hoping to fix this issue at some time, and make it so we don't have to call that method. I just haven't had time recently.)

Wrapping Up The Map

The rest of the map (the one remaining "name" property being mapped, in this case) is a regular NHibernate map. You'll notice, though, that we never mapped the "DispalyForFullfillment" property. I explicitly choose to leave any and all "volatile" properties out of my state maps. By doing this, I am able to add, edit, and remove any properties or methods on the state objects that I need, without having to change the NHibernate mappings. Since the state objects I am dealing with don't change without recompiling the code anyway, I don't need the ability to define them in the database. However, if you do need or want the flexibility of defining your states in the database, you can map each individual property of the state. Just remember that you will have to modify both the code and the database, to make the changes complete.

I hope this quick look at mapping a state pattern with Fluent NHibernate will help to shed some light on the subject, for someone. I realize that I have only provided the FluentNHibernate mapping, though. I specifically chose to do this because it would be a serious chore for myself to create a code project with NHibernate set up so that I can actually verify my mapping xml is correct. However, the translation from FluentNHibernate back to standard .hbm.xml files should be fairly straightforward, with the help of the NHibernate Documentation. If anyone out there is willing to help out and send me the correct .hbm.xml mapping, I would be more than happy to add it to this post and credit you with the work.



_________________________________
Cross Posted From LostTechies.com
Wednesday, November 26, 2008 10:42:11 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Data Access | Design Patterns | Lambda Expressions | NHibernate | Principles and Patterns

 Tuesday, October 28, 2008

In my last post, I talked about the idea of encapsulation and using it to ensure that our business rules were enforced correctly. What I didn't talk about, though, was the second half of the conversation that my coworker and I had, concerning the patent -> consultation relationship. It turns out that we had the relationship wrong. That's not to say that patients don't have consultations, but that the logical model we were traveling with had an incorrect perspective and was causing us to create some very ugly workarounds in various parts of the system. What really stuck out in my mind, though, was not the idea that we had the model wrong, but how we came to the conclusion of the model being wrong. It has become apparent to me, upon reflection of the conversations and situation as a whole, that design smells are not always evidenced by design related activities, if ever.

A Persistent Problem - Duplicate Redundancy

After some initial coding of the patient -> consultation relationship, we start working on the persistence model via NHibernate. What we have is a patient with a collection of consultations - this is easy to map with NHibernate's one-to-many capabilities. We also have a CurrentConsultation property which needs to be mapped. This property is mapped to the same Consultation table, but only pull one specific consultation based on the business rules that state the current consultation is chronologically the most recent and has not ending date set.

After some thought, we found that there were a few possibilities for handling the CurrentConsultation property in our current model:

  1. Create a "CurrentConsultation" object that is mapped to the Consultation table and use a "where" class attribute in the NHibernate mapping that would limit the returned result
  2. Create a "CurrentConsultation" object that is mapped to a CurrentConsultation view and have the view coded to return the correct consultation object
  3. Add a CurrentConsultationId field to the Patient table, as a foreign key to the Consultations table, and map to the existing Consultation object

After some additional thought, though, we found that each of these solutions has a few significant problems that were going to cause a lot of trouble.

Options 1 and 2

Both of these options have the problem of duplicating business rules into more than one language and location. We would either have the business rules of what constitutes the current consultation in the NHibernate mapping (the 'where' attribute) or in a database view, in addition to the already existing code. Changing the rule would mean changing a minimum of two locations where that rule is handled. This is a bad idea no matter how you look at it.

Both of the options have also created a duplication of knowledge from the concept of a Consultation by creating a "CurrentConsultation" class and a separate NHibernate map for it. We would have the original Consultation class and the new CurrentConsultation class both representing the same data, making an artificial distinction in our code. Again, this is a bad idea. We don't want duplication of these logical concepts. We're also not dealing with a bounded context or any other logical separation of concerns at this point, so there is no need to separate the concept of a consultation into multiple classes.

Option 3

This doesn't appear to have the duplication issue in code, but there is a potential for duplication of data. When we get down to the implementation of NHibernate, we could easily cause duplicate data in the consultation table by saving the current consultation class. We might be able to get around this by not cascading the saves of the current consultation property, but then we'd be forced to ensure the consultation collection was persisted prior to the patient so that we could update the current consultation object's id before saving the patient. Both of these problems sound like a serious pain to me. I'm betting it's possible, but I'm also betting that it would be a nightmare of trial and error to get it right and a lot more code than we should really have to write.

Changing Perspectives

As Joe Ocampo pointed out in the comments of my original post, we had a problem in our system that was really caused by our lack of correct perspective in the situation. Rather than forcing the idea of a patient being the root aggregate in this situation, causing us a lot of headache and frustration in trying to model our persistence layer, a simple change in how we looked at the situation helped us solve the persistence problem and greatly simplified how the application worked.

Joe's comment (with some formatting added):

"One thing I like to challenge developers with when I teach DDD is to flip the aggregate to determine if the model is sound.

I know this is only an example but work with me here.  You indicated you are dealing with a medical system.  We can assume there are certain entities such as Patient, Consultations, Doctor and Practice. In your example you created a model where the patient is the aggregate root for consultations but what if the Doctor simply asked what consultations do I have today?  In this paradigm the Practice is the aggregate root and Consultations are aggregate within where Patient is an aspect of the consultation.  The code would look something like this.

consultations = practiceService(IConsultationService).GetConsultationsFor(doctor);

This also allows the consultation service to encapsulate its own logic for creating a consultation for creating a consultation. You can’t get any closer than that :-)

consultationService.CreateConsultationFor(patient).with(doctor).at(date);

The point I am trying to make is be careful of aggregate roots.  Once you go down that path it is really difficult to back the train up and break it apart."

Though our actual implementation was different, this was the same basic conclusion that we had come to - our perspective on the situation was simply wrong. When we stepped back from the problem and realized that the consultation was the primary focus of the situation, and that a nurse or doctor would be the primary user of that portion of the system, it became rather obvious that our aggregate was in dire need of rework.

A Reflective Perspective

What we ended up with was a Patient object that dealt with all of it's demographics information, billing information, etc, without a CurrentConsultation property or even a Consultations list. Then, on the the separated Consultation object, we added a child property of Patient. Once we realized that our Consultation object was the primary focus and made this distinction in our code, we also realized that the Patient object was carrying far too much information around the system. We found that we actually had two very distinct concepts of a patient, determined by two very distinct bounded contexts.

  • In the 'Billing' context, we needed all of the address , billing, and other demographics information about the patient - who they are, where they live, what their insurance is, etc. The existing Patient class filled this need.
  • In the 'Consultations' context, we did not need anything from the Billing context, except for the person's name and patient id. What we really care about in the consultations is medical information about the patient - their current prescriptions, allergies, past medical care, etc. So, we created a ' patient' class to represent these needs.

These changed allowed for a much more clearly defined model that was truly reflective of the systems needs. We could easily see the difference between a 'billing' patient and a 'medical' patient, and we were able to code each of these areas of the system without the concerns bleeding into each other. Essentially, we decoupled the system at a module level, not just at a class level.

We also found that the NHibernate mapping problems suddenly went away. Since the Consultation class had a child of Patient, it was a simple many-to-one mapping with no strange sequencing or duplicate data issues. In the screens that deal with the consultation directly, we load the consultation as the aggregate root and go from there. In the screens that need to show patient consultation history, we did a simple query and returned all of the consultations for the given patient. Again, we found a way to decouple our system - this time, at the persistence model.

Design Smells: Not Just A Design Problem

In the end, we were able to recognize a serious design smell in our system - not by the design itself, though. After all, the original code had encapsulated the needs quite well. But, as it turns out, it was a bad encapsulation at a higher level. It wasn't until we started working with the model we had created, specifically trying to persist the model, that we realized our design was not right.

This change was a huge breakthrough for us, not necessarily in the code or the system that was being built, but in how we look at our systems and our domain models. The realization that design smells are often evidenced not by the design itself, but by how the design is used in the infrastructure and other supporting roles of the system, has had a profound impact on how we look at system design. I'm now seeing areas of different systems that are encapsulated incorrectly, at a higher level than class design. Recognizing the problem is the first step - and we're now working to rearrange and invert these models to more accurately reflect reality.

Pay attention to the pain that your application, infrastructure and other supporting services are causing you. You may be staring at evidence of a design problem, without realizing it.



_________________________________
Cross Posted From LostTechies.com
Tuesday, October 28, 2008 2:45:45 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Analysis and Design | Data Access | Design Patterns | Domain Driven Design | NHibernate | Principles and Patterns | Refactoring

 Sunday, July 27, 2008

Some coworkers were recently working on an object model for a simple security system. After some discussion with them, we came up with this basic model:

image

A permission is defined as an activity that can be assigned to a user, or group, and can be allowed or disallowed. From a Domain Driven Design perspective, we're stating that the Permission is the aggregate root. The User object itself, while involved in this aggregate, is divorced from this aggregate's relational model - you can load and work with a User object without having to load or worry about the Permission hierarchy. The addition of the "UserGroup" is solely for the many-to-many relationship between User and Group mappings with NHibernate and is not actually part of the object model's code.

Once we had this model in place, we wanted to have a simple query that allowed us to load a given permission object by activity name, for a user - whether the user was assigned directly or via a group. At a high level, this model and query should be fairly simple to work with. It turned out to be a massive learning curve in NHibernate, though.

After much trial, error, and Google searching, we ended up with this NHibernate query code:

ICriterion userIdMatches = Restrictions.Eq("Id", userId);
ICriterion activityNameMatches = Restrictions.Eq("Name", action);
ICriterion userIdAliasMatches = Restrictions.Eq("u.Id", userId);
 
DetachedCriteria groupPermissionCriteria = DetachedCriteria.For<Permission>()
    .SetProjection(Projections.Property("Group"))
    .CreateCriteria("Group").CreateCriteria("Users").Add(userIdMatches);
ICriterion groupSubquery = Subqueries.PropertyIn("Group", groupPermissionCriteria);
 
 
DetachedCriteria permissionCriteria = DetachedCriteria.For<Permission>()
    .CreateAlias("User", "u", JoinType.LeftOuterJoin)
    .Add(Restrictions.Or(userIdAliasMatches, groupSubquery));
permissionCriteria.CreateCriteria("Activity").Add(activityNameMatches);
 
 
ICriteria executableCriteria = permissionCriteria.GetExecutableCriteria(Session);
result = executableCriteria.List<Permission>();
 
 
return result;

There were a lot of lessons learned and a lot of parts that eventually got put together. Here's a quick run-down of what we ended up with and why.

  • The ICriterion's at the top of this code block are there to provide a little better readability in the real query code below.
  • The groupPermissionCriteria is set up to find a permission object where the specified userId belongs to a Group that belongs to the Permission - i.e. find permissions where the user is assigned via a group. The learning curve from this perspective was the SetProjection call. Though we are not entirely sure what a projection is at this point, we did find out that it was necessary for us to set this projection so that the detached criteria could be used as a sub-query.
  • The groupSubQuery is the conversion of the groupPermissionCriteria into an ICriterion so that we can do a logical Or with it in the primary query construction.
  • The permissionCriteria object sets up the core criteria logic and ties together the group permission assignment with the user permission assignment.
  • CreateAlias is used so that we can shorten the criteria for loading by the User assignment directly. The JoinType on the alias needs to be Left Outer Join so that we will return a proper Permission object even when there is no direct user assignment.
  • After creating the alias, we can add an "Or" criterion to the query and specify that we want to match based on the user's direct assignment or a group's assignment.
  • The last line of the criteria simply adds the Activity criteria to load by the activity name.

The resulting SQL will load the permission by Activity name AND (User assignment OR group assignment where the user is part of the group).

SELECT 
 
                this_.PERMISSIONSID as PERMISSI1_0_3_, 
                this_.IS_ALLOWED as IS2_0_3_, 
                this_.ACTIVITYID as ACTIVITYID0_3_, 
                this_.USERID as USERID0_3_, 
                this_.GROUPID as GROUPID0_3_, 
                activity1_.ACTIVITYID as ACTIVITYID4_0_, 
                activity1_.ACTIVITY_NAME as ACTIVITY2_4_0_, 
                activity1_.DESCRIPTION as DESCRIPT3_4_0_, 
                activity1_.INACTIVE_DATE as INACTIVE4_4_0_, 
                u2_.USERID as USERID3_1_, 
                u2_.USER_NAME as USER2_3_1_, 
                u2_.INACTIVE_DATE as INACTIVE3_3_1_, 
                group6_.GROUPID as GROUPID1_2_, 
                group6_.GROUP_NAME as GROUP2_1_2_, 
                group6_.INACTIVE_DATE as INACTIVE3_1_2_ 
FROM PERMISSIONS this_ 
                inner join ACTIVITY activity1_ 
                                on this_.ACTIVITYID=activity1_.ACTIVITYID 
                inner join USERS u2_ 
                                on this_.USERID=u2_.USERID 
                left outer join GROUPS group6_ 
                                on this_.GROUPID=group6_.GROUPID 
WHERE 
                activity1_.ACTIVITY_NAME = :p1
                and 
                (
                                u2_.USERID = :p2 
                                or 
                                this_.GROUPID = 
                                (
                                                SELECT 
                                                                this_0_.GROUPID as y0_ 
                                                FROM PERMISSIONS this_0_ 
                                                                inner join GROUPS group1_ 
                                                                                on this_0_.GROUPID=group1_.GROUPID 
                                                                inner join USERS_GROUPS users5_ 
                                                                                on group1_.GROUPID=users5_.GROUPID 
                                                                inner join USERS user2_ 
                                                                                on users5_.USERID=user2_.USERID 
                                                WHERE 
                                                                user2_.USERID = :p3
                                )
                )

Using a sub-query to load based on the group is not the most optimal way of loading the permission for the group assignment. However, since all of the joins in the main query and the sub-query are done on primary and foreign keys in the tables, performance should not be an issue. The only real performance concern for this query is the activity name in the where statement. A simple unique constraint and index on the activity name, though, will solve that problem.

Sunday, July 27, 2008 1:55:08 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Data Access | Domain Driven Design | NHibernate

 Thursday, June 19, 2008

I'm currently working on a search screen for a shipment tracking system.  At the bottom of this screen, there are 4 checkboxes that will determine whether or not we are supposed to display Imports, Exports, Air shipments, or Ocean shipments - in whatever combination the user wants:

image

Down in the depths of the search process, I am creating a "finder" object, as Ayende talked about quite a while back. In this object, I have to account for the checkbox values here - whether or not the user wants to display whatever types of shipment (import or export) and/or the method of shipment (air or ocean). What gets really interesting is that when a box is un-checked, I should not show that particular type or method.

A quick analysis of these 4 checkboxes will come up with the following variants that must be accounted for when building the query.

  1. Show Imports Only
    1. Ocean and Air
    2. Ocean only
    3. Air Only
  2. Show Exports Only
    1. Ocean and Air
    2. Ocean only
    3. Air only
  3. Show Imports and Export
    1. Ocean and Air
    2. Ocean only
    3. Air only
  4. Show no imports or exports (returns no results)
  5. Show no ocean or air (returns no results)

All totaled up, that's 11 different query variants that have to be accounted for.

The end result of my query build methods is the following:

private void AddShipmentMethodCriteria(DetachedCriteria criteria)
{
    ICriterion air = Restrictions.Eq("ShipmentMethod", "Air");
    ICriterion ocean = Restrictions.Eq("ShipmentMethod", "Ocean");
 
    if (searchCriteria.ViewAirShipments && searchCriteria.ViewOceanShipments)
        criteria.Add(Restrictions.Or(air, ocean));
    else
    {
        if (searchCriteria.ViewAirShipments)
            criteria.Add(air);
        else
            criteria.Add(Restrictions.Not(air));
 
        if (searchCriteria.ViewOceanShipments)
            criteria.Add(ocean);
        else
            criteria.Add(Restrictions.Not(ocean));
    }
}
 
private void AddShipmentTypeCriteria(DetachedCriteria criteria)
{