Pragmatic Developer

Ali Özgür

Bookmark Blog

Add to Technorati Favorites

Google Talk

Chat with Ali Özgür

Purchase PragmaSQL from

Calendar

«  November 2008  »
MoTuWeThFrSaSu
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567
View posts in large calendar

Tag Cloud

Don't show

    Authors

    Recent Comments

    Banners




    Here is aother strange problem related with NHibernate

    The Problem

    I have a Parent class and two child classes Child1 and Child2 mapped to different tables on the database.
    Lets assume that we specified cascade='all' for child bags defined on Parent.hbm.xml. Sample workflow of instantiating parent and child objects is as the following

    - Create a parent object.
    - Insert 2 Child1 instances to child1 bag
    - Insert 3 Child2 instances to child2 bag.
    - Flush the session
    - Refresh parent object
    - We get 6 instances for each child bag (child1 and child2). But we expect 2 Child1 instances in child1 bag and 3 Child2 instances in child2 bag.

    Ther problem is : NHibernate performs left outer join on Child1 and Child2 tables when Refresh is called for the parent object. This is unaccaptable, I think NHibernate should initialize child collections with seperate selects commited to the database, or may be distinguish the duplicated child instances automatically in the collections. (using idbag instead of bag is not an option)

    Download the test case

    Requirements

    Watch This


    Posted in: .NET Development , C# , NHibernate  Tags:

    Be the first to rate this post

    • Currently 0/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5

    I discovered this problem while developing a new system with the latest NHibernate.Burrow distribution (which in turn uses the latest NHibernate distribution). I spent some time Googling around to check if anyboy else met the same problem and found some entries but none of them specified exactly why this failure was happening and how we can solve this problem.

    The Problem

    My code simply executes the following steps

    1. Call a factory method
    2. Create a Curve
    3. Create CurveInterval objects
    4. Put CurveInterval objects inside the Curve.Intervals collection
    5. Call the same factory function to create another Curve instance
    6. Before creating Curve instance I perform some checks with HQL , this causes session to be flushed automaticaly
    7. I get the error when session is about to be flushed automatically

    001 <?xml version='1.0' encoding='utf-8'?> 
    002<hibernate-mapping xmlns='urn:nhibernate-mapping-2.2'> 
    003<class 
    004name='GradeEntry.Domain.Curve, GradeEntry.Domain' 
    005      table= 'LetterGrade'> 
    006<id name='Id' 
    007column='LG_ID' 
    008unsaved-value='0'> 
    009<generator class='native'/> 
    010</id> 
    011
    012<version name='ManagedVersion' column='NhVersion' type="System.Int64" unsaved-value="0"/> 
    013
    014<property name='DateCreated'/> 
    015<property name='CreatedByPersonId'/> 
    016<property name='Locked'/> 
    017<property name='LockChangedById' column ='LockChangedByID'/> 
    018<property name='LockChangedOn'/> 
    019<property name='LockMessage'/> 
    020<property name='LogIdx'/> 
    021<property name='LogCnt'/> 
    022<property name='IsStable'/> 
    023
    024<bag name='Intervals' 
    025order-by='LetterID asc' 
    026table='LetterGradeList' 
    027access='field.camelcase-underscore' 
    028inverse='true' 
    029cascade='delete-orphan, save-update' 
    030lazy='true'> 
    031<key column='LG_ID'/> 
    032<one-to-many class='GradeEntry.Domain.CurveInterval, GradeEntry.Domain' /> 
    033</bag> 
    034
    035<bag name='Log' 
    036order-by='Idx asc' 
    037table='LetterGradeLog' 
    038access='field.camelcase-underscore' 
    039inverse='true' 
    040cascade='delete-orphan,save-update' 
    041lazy='true'> 
    042<key column='LG_ID'/> 
    043<one-to-many class='GradeEntry.Domain.CurveLog, GradeEntry.Domain' /> 
    044</bag> 
    045
    046</class> 
    047</hibernate-mapping>
    048
    049
    050

     

    First Attempt To Reporoduce The Problem

    I have prepared a sample project but I was not able to recreate the bug, and I know it is hard to tell what is the problem under these conditions. But I have some more findings about this issue.

    - When I replace cascade of the bags to 'all-delete-orphan' from 'delete-orphan,save-update' everything is ok
    - When I replace cascade of the bags to 'all, delete-orphan' from 'all-delete-orphan' I still get the assertion failure.

    I think the problem is with the new implementation of cascade which is intended to support comma seperated list of cascade options.

    Second Attempt To Reporoduce The Problem

    After spending some more time trying to diagonise the problem I finally succeeded to reprouce the problem with atest case. I attached the test case.

    Simply the problem resolves to something like this.

    NOTE: All classes utilize managed versioning by defining ManagedVersion.

    1. I create 2 parent objects save them , flush the session and refresh them
    2. Then for each parent object I create some child objects of type Child1
    3. I perform HQL to get all Child3 instances. Child3 class does not have any association or cascade relation with Parent, Child1, Child2 and ParentRef classes. The HQL I performed causes the session to auto flush thus inserting Child1 instances to the database. But somehow while auto flushing the session versions of the parent objects are not updated. I expect two updates to be submitted to the database for parent objects since we associated Child1 instances with the parents and that must cause a version increment on parent objects.
    4. Then I try to perform another HQL query to get list of ParentRef objects and I get assertion failure. Note that ParentRef class is associated with Parent class which in turn defines cascade for Children1 and Children2 collections.

    If we do not perform the HQL in step 3 Child1 instances will be inserted to the database and parent objects will be updated while performing the HQL in step 4 and we will not get the assertion failure.

    I covered both cases in the attached test case.

    Database scripts are included under DBScript folder.

    Download test case

    Requirements

    Watch This

    See Also


    Posted in: .NET Development , C# , NHibernate  Tags:

    Be the first to rate this post

    • Currently 0/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5

    GoF book says that "Observer pattern should defina a one-to-many dependency between objects so that when one object changes state, all its dependenst are notified and updated automatically". Subscribing to RSS feeds is a nice analogy.  You subscribe to RSS feeds to show interest and you become an observer who demand for notification and RSS feeds become the subject and are responsable for providing information to all subscribers. I think this bit of information describing the pattern is enough, now lets see how we implement observer pattern.

    Lets assume that we are developing a car controller software. One of the requirements is "Provide visual warning to the driver if seat belts are not locked". To meet the requirement we design

    • SeatBelt class which is the subject. This class should notify interested objects about the state changes
    • SeatBeltMonitor class is our observer. This class monitors for status change messages provided by the SeatBelt and displays messages

    Implementing Observer Pattern in conventional way 

    Download GoF_Patterns_Observer1.rar (20,36 kb)

    It is suggested to specify an interface or abstract classes when dealing with patterns so that the objects we create will adhere to some predefined contract. So we start our implementation by specifying two interfaces ISubject and IObserver

    001    public interface ISubject
    002    {
    003        void RegisterObserver(IObserver observer);
    004        void RemoveObserver(IObserver observer);
    005    }
    006
    007    public interface IObserver
    008    {
    009        void Update(bool locked);
    010    }

    As I've mentioned above our SeatBelt class is the subject (source) of the state change and should implement the contract so that interested parties shall define their interest to the state changes More...


    Posted in: C# , GoF Patterns  Tags:

    Currently rated 4.0 by 1 people

    • Currently 4/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5

    I believe Factory Pattern is one of the most known pattern in development community. Simply Factory Pattern states that we have a factory object which is used to create other objects. But GoF specification for the Factory Pattern is a little bit different. GoF book says that "We should define an interface for creating an object, but let subclasses decide which class to instantiate." 

    How you implement the Factory Pattern depends on your custom needs. 1) If you want to control object instantiation behaviour of your factory provide a static class with static methods or sealed factory class to your clients, else 2) if you want to keep your code closed for modification but open for extension follow the GoF way by providing an interface or abstract factory class.

    Method 1

    Download GoF_Patterns_Factory1.rar (18,45 kb)

    Now lets implement Factory Pattern for our Vehicle instantiation process so that we do not want our clients to have alternative factory implementation at all.

    001   //Abstract Vehicle class
    002    public abstract class Vehicle
    003    {
    004        public abstract string Description { get; }
    005    }
    006    
    007    //Concrete implementation
    008    public sealed class Car : Vehicle
    009    {
    010        internal Car() { }
    011        public override string Description
    012        {
    013            get { return "Car";}
    014        }
    015    }
    016
    017    //Concrete implementation
    018    public sealed class Helicopter : Vehicle
    019    {
    020        internal Helicopter() { }
    021        public override string Description
    022        {
    023            get { return "Helicopter"; }
    024        }
    025    }
    026
    027    //Concrete implementation
    028    public sealed class Jet : Vehicle
    029    {
    030        internal Jet() { }
    031        public override string Description
    032        {
    033            get { return "Jet"; }
    034        }
    035    }

    I've chosen to implement my factory More...


    Posted in: C# , GoF Patterns  Tags:

    Be the first to rate this post

    • Currently 0/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5