Wednesday, November 30, 2011

P2PMapper

If you're working with MVVM, you're probably familiar with the case in which one property depends on another property. 
For instance, consider the following 'User Registration' form. 




In this registration form, the 'SMS' checkbox is enabled only if the user entered a phone number and checked the 'Receive Messages' checkbox. The same goes for the 'Mail' checkbox - it is enabled only if the user entered an email address and checked the 'Receive Messages' checkbox.

To implement the above behavior you'll probably create the following properties in the ViewModel and bind them to the 'IsEnabled' of the 'SMS' and 'Mail' checkboxes:

        public bool EnableSMS
        {
            get
            {
                return ReceiveMessages && !string.IsNullOrEmpty(Phone);
            }
        }

        public bool EnableMail
        {
            get
            {
                return ReceiveMessages && !string.IsNullOrEmpty(Mail);
            }
        }

But now, 'EnableSMS' depends on 2 other properties - 'ReceiveMessage' and 'Phone'. Whenever these 2 properties are changing - the UI needs to be notified that the 'EnableSMS' has changed too. The same goes for 'EnableMail'.
So, to support that, you probably have the following code:

        public string Phone
        {
            get
            {
                return _phone;
            }

            set
            {
                _phone = value;
                NotifyPropertyChanged("Phone");
                NotifyPropertyChanged("EnableSMS");
            }
        }

        public string Mail
        {
            get
            {
                return _mail;
            }

            set
            {
                _mail = value;
                NotifyPropertyChanged("Mail");
                NotifyPropertyChanged("EnableMail");
            }
        }

        public bool ReceiveMessages
        {
            get
            {
                return _receiveMessages;
            }

            set
            {
                _receiveMessages = value;
                NotifyPropertyChanged("ReceiveMessages");
                NotifyPropertyChanged("EnableSMS");
                NotifyPropertyChanged("EnableMail");
            }
        }

I guess you will agree with me that the code is starting to get messy...

Now, there are several tools that can handle this situation, like Update ControlNotifyPropertyWeaver or this one and some of them are doing it quite well.

But as far as i know, none of the above tools supports the case in which one property depends on a graph of objects.
For example: the company's total salaries would be the sum of all Company.Employees.Salary.Amount.
For instance, consider the following 'Edit Salaries' screen:


The ViewModel of this screen has a 'Company' property. The grid is bound to Company.Employees and the Salary column is bound to 'Employee.Salary.Amount'.
The Total Salaries field in the bottom of the screen would be bound to a property called 'TotalSalaries' on the ViewModel and it will look like this:

        public double TotalSalaires 
        {
            get
            {
                return Company.Employees.Sum(x => x.Salary.Amount);
            }
        }


Now, if for some reason the 'Company' property would change - 'TotalSalaries' would change as well. But the UI wouldn't know about it because it has no way to know that 'TotalSalaries' depends on 'Company'.
And what if 'Company.Employess' would change? What if the 'Salary' of an employee would change, or the 'Amount' of a salary would change? The UI wouldn't know that 'TotalSalaries' needs to be re-invoked.

For this I've came with a solution called: P2PMapper which stands for: Property to Property Mapper.
Let's see how it works.
In the first example above i would use it like this:

            P2PMapper<UserRegViewModel>.Init(this)
                .Couple(x => x.EnableSMS)
                .With(x => x.ReceiveMessages)
                .With(x => x.Phone)
                .Couple(x => x.EnableMail)
                .With(x => x.ReceiveMessages)
                .With(x => x.Mail);

This code can be set in the ViewModel's constructor.
I pass the class of the ViewModel as a generics parameter.
Then i pass the instance of the ViewModel to the Init method.
Then i Couple the 'EnablePhone' property (of the ViewModel) With the 'ReceiveMessage' and 'Phone' properties and so forth.

Of course that,
NotifyPropertyChanged("EnableSMS");
and
NotifyPropertyChanged("EnableMail");
can now be removed from anywhere in the code.

In the second example above i would use it like this:

            P2PMapper<CompanyDetailsViewModel>.Init(this)
                .Couple(x => x.TotalSalaires)
                .With(x => x.Company.Employees[0].Salary.Amount);
Now, whenever there is a change down the path of Company.Employees.Salary.Amount - the P2PMapper will track it down and notify the UI about it.

NOTE: x.Company.Employees[0] is only a syntactic way to get down the path, it doesn't really mean 'the first employee'.


NOTE: each object down the path, including the ViewModel itself, needs to implement the interface P2PMapper.INotifier. Also, each property down the path must call NotifiyPropertyChanged when ever it is changing.


The sample code, including the P2PMapper.dll can be found here

Sunday, November 13, 2011

NHibernate bi-directional - use it carefully (Part II)

In the previous post I've showed you one reason to be very careful when using bi-directional associations in NHibernate.

In this post I'll show you another reason. Again, for the example, I will use Customer with many Orders.

We will create a one-to-many association from Customer to Orders:
<set name="Orders" lazy="true" cascade="all-delete-orphan">
      <key column="CUSTOMER_ID" />
      <one-to-many class="Order" not-found="ignore"/>
</set>

and we will create a many-to-one from Order to Customer:
<many-to-one name="Customer" class="Customer" column="CUSTOMER_ID"/>
Now consider the following scenario:
someCustomer.Orders.Add(someNewOrder);

...query the db using HQL

...

someNewOrder.OrderDate = DateTime.Now;

....

CustomerRepository.SaveOrUpdate(someCustomer);
transaction.Commit();

If you'll take a look at table 'ORDERS' right after the commit, you'll find out that the CUSTOMER_ID field in the new record created for someNewOrder is... NULL.

And why is that?
let's see what NHibernate is doing a step by step:
1 - Right before querying the DB by using HQL, NHibernate is flushing all the changes to the DB, and that includes creating a new record for someNewOrder At this stage the record in the DB is perfectly well.

2 - By changing someNewOrder.OrderDate NHIbernate considers someNewOrder as 'dirty' and it will flushed it to the DB later on when the transaction will be commited.

3 - Finally, when the transaction is commited, again NHibernate is flushing all the changes but this time it's generating an 'UPDATE' statement for someNewOrder since it's no longer a new object - it has a record in the DB.

And here is the problem - as we saw in the last step, an 'UPDATE' statement for someNewOrder
is executed. But since someNewOrder.Customer is null (nowhere in the code we've ever changed it) - the 'UPDATE' statement looks something like this:
"UPDATE ORDERS SET ...CUSTOMER_ID=NULL... WHERE...".

OK, now you have a few options to solve it:
1 - do not use HQL - use session.Get() instead (only if you can...). This doesn't enforce NHibernate to flush like HQL does.

2 - You can make sure that someNewOrder.Customer actually does hold the Customer before committing.

3 - You can go to Order.hbm.xml and add update="false" to the many-to-one association. like this:
<many-to-one name="Customer" class="Customer" column="CUSTOMER_ID 
update="false"/>
this tells NHibernate not to include the Customer when generating an 'UPDATE' statement for an Order.
But this also means that you can not update the Order's Customer like this:
someOrder.Customer = someCustomer;
OrderRepository.SaveOrUpdate(someOrder);
it won't work if you chose option No. 3...

Thursday, November 10, 2011

NHibernate bi-directional - use it carefully (Part I)

A few days ago we've experienced a very strange behavior with NHibernate. Or so we thought... 
For the demonstration i will use a Customer that has many Orders. 

And so we did that:
customer.Orders.Remove(order);
CustomerRepository.SaveOrUpdate(customer);

The "strange" behavior was that the Customer itself has been deleted from the DB along with all of its other Orders.

the mappings were like this:

Customer.hbm.xml:
<set name="Orders" lazy="true" cascade="all-delete-orphan">
     <key column="CUSTOMER_ID" />
     <one-to-many class="Order" not-found="ignore" />
</set>


Order.hbm.xml:
<many-to-one name="Customer" class="Customer" column="CUSTOMER_ID" cascade="all-delete-orphan"/>


So, what went wrong? Why did NHibernate delete the customer when all we did was removing one order? the reason was:

When we removed one Order from the Customer.Orders list, NHibernate deleted this Order from the DB since we have cascade="all-delete-orphan" on Customer.Orders. 
But while deleting an Order, NHibernate also is deleting its Customer. Why? Because we have 
cascade="all-delete-orphan" on Order.Customer, meaning - we actually tell NHibernate to delete a Customer whenever one of its Orders is being deleted. And that's usually a stupid thing to do.



Tuesday, November 1, 2011

Strongly Typed HQL


If you're using NHibernate, you have 3 main options to execute a query against the DB: Criteria API, HQL and SQL. The last one won't be relevant to our discussion.

For a long time, the names of the properties were a weakness point since they were represented by strings. For example:

var crit = Session.CreateCriteria(typeof(Person));
crit.Add(NHibernate.Criterion.Expression.Eq("ID", someVal));

Lately, Criteria API has an extension to support Lambda expressions and therefore can be strongly typed:

var crit = Session.CreateCriteria(typeof(Person));
crit.Add<Person>(p => p.ID == someVal)

But in some complicated cases - HQL is inevitable, and since HQL is represented by string - refactoring can be very painful. For example:

string hql = "select p from Person p where p.ID=:someVal"

To avoid this problem, I've created 2 methods. To use these methods, simply locate them in the base class of all the classes that build HQL quries. In our case it was BaseRepository which is the base class for all the Repositories (if you're following DDD). These 2 methods are:

Class<T>();
Prop<T>(Expression<Func<T, object>> property);

I will show the implementation soon, but first an example:

string hql = "select p from " 
+ Class<Person>() + " p where p." + Prop<Person>(x => x.ID) + "=:someVal"

And the implementation:

public string Class<T>()
{
    return typeof(T).ToString();
}

public string Prop<T>(Expression<Func<T, object>> property)
{
    if (property.Body.NodeType == ExpressionType.MemberAccess)
    {
        return (property.Body as MemberExpression).Member.Name;
    }
    else if (property.Body.NodeType == ExpressionType.Convert
        && (property.Body as UnaryExpression).Operand.NodeType == ExpressionType.MemberAccess)
{
        return ((property.Body as UnaryExpression).Operand as MemberExpression).Member.Name;
}

    return "";
}

WCF - a performance issue

A few weeks ago I've encountered an annoying performance problem with WCF.

We were working on some Client/Server application, which should work only inside a local network, meaning - all the clients will be connected to the server via the Intranet. We were using WCF of curse.
While doing QA we've faced a problem - one client worked really fast and the other was a bit slow. They both had the same server and they both had the same hardware, OS, installations etc.

After smashing my head against the wall a few times I've found the problem: the slower one wasn't configure to bypass proxy for local addresses and that caused an overhead.

To find out your configuration - open Internet Explorer->Tools->Internet Options->Connections->LAN Settings


So, instinctively, the first solution that came to my mind was to re-configure the machine to bypass proxy. But then i thought - it doesn't make any sense - i cannot enforce the users on the field to change their configuration. And so I've found a better solution - on the client side configure the binding as follow:

binding.UseDefaultWebProxy = false;
    
or on the App.config file:

<binding name="httpBind" .... bypassProxyOnLocal="true">
Since the system was planed to work inside the Intranet - we don't need to use proxy anyway.

Bye.