Development of parent/child relationships across application layers - also AutoMapper, a WPF custom converter, and WPF shutdown.

Chapter XII

Chapter XIV

The series

WCF by Example is a series of articles that describe how to design and develop a WPF client using WCF for communication and NHibernate for persistence purposes. The series introduction describes the scope of the articles and discusses the architect solution at a high level. The source code for the series can be found at CodePlex.

Chapter overview

At this point in the series, we have covered the most important infrastructure components; however, our business domain consists of a single entity which doesn't help to explain how to resolve some common scenarios when designing parent-child relationships across different application layers. In this chapter, we are introducing a new entity to the model so we can describe how the above mentioned cases might be resolved.

At the end of this chapter, in the appendix section, we also discuss the following topics:

The entity has a reference to the Customer reference (line 02) so we will have a one-to-many relationship. As we did with the Customer class, we hide the constructor (line 01) so the Create static method (line 03) needs to be invoked when a new instance is required.

The Customer class needs some re-factoring to accommodate for the new Address class; couple important points are that the Customer class will be responsible for the creation and deletion of Address instances and that the collection of addresses is not exposed directly to ensure the collection is well managed; see also how ISet needs to be used because of NHibernate:

Instead, the collection is exposed by cloning the collection into a ReadOnlyCollection (line 01). If a new address needs to be added to the customer, the AddAddress method must be used (line 02); the same applies when an address is to be removed (line 03).

As a result of the above changes, the domain model is as follows:

The following changes need to be added to the NHibernate mapping file:

In the Customer mapping, the private AddressSet collection is declared as a one-to-many collection of Address instances; we indicate that the Customer_ID field in the Address table is used as the link (line 01). In the Address mapping section, we also declare the Customer reference to use the same column name (line 02). This approach permits to navigate from the child back to the parent.

Let's demonstrate how easy it is to propagate the changes to our database; if we create a new test:

and the configuration is set so the test is run using the NHibernate mode, then the test will generate the new schema for us, isn't that nice? Just remember to change the test App.config file:

You may want to open a connection to the database to see the new schema:

New address service

We are planning to modify the user interface so the following screens will be available:

We need to provide a new service so we can create, retrieve, and update an Address instance:

Adding a new service requires the following:

Add the new interface to the IContractLocator

There are three implementations of the interface that need to be updated

Add three new AddressServiceProxy, AddressServiceAdapter, and AddressWcfService classes

The implementation of the above classes is straightforward as they are in fact very similar to the implementations for the Customer service; you may want to get the source code for further details.

In the server side, we need to amend eDirectory.WcfService to add the new Address service to the list of endpoints:

Notice that the model provides class holders for the selected grid rows; this works in both ways, which is very nice. The only thing to do in the View is to set the binding correctly:

It may not be obvious, but when the list of clients is retrieved from the server, each customer DTO contains a collection of addresses. You may implement a more chatty design where the address collection is only retrieved when the customer is selected. Also, the Customer reference in the Address class translates into the DTO implementation in storing the CustomerId instead; if you don't take this approach, the serialization of your DTOs would be a nightmare, to say the least:

There is another interesting aspect on the AgendaViewModel, that is the way we manage the action buttons using the RelayCommand class. In this case, if a customer instance contains an address, the user needs to delete all addresses before the Delete button for the customer is enabled. This is achieved easily by implementing a predicate in the RelayCommand constructor using the above mentioned selected holder:

Another aspect implemented is something that we have not had a chance to see before; this is how the ViewModel and Services use the selected customer DTO to enhance the user experience; for example, when a new customer instance is created, we need to ensure that the new customer instance is the one selected in the grid once the user is back to the main screen. We resolve this requirement as follows:

There is a little bit of code above, but bear with us for a second; the CreateCustomerCommand delegates to the OpenCustomerDetail method (line 01), this method calls the customer detail screen and if a new customer instance is created, it sets the SelectedCustomer property in the Model (lines 02 and 03). Then the Refresh method is called which invokes the CustomerServiceInstance.FindAll() and sets the Model.SelectedCustomer (line 05) to the value it had before the service was called.

Chapter summary

Parent-child relationships are common in all applications; in this chapter, we discussed how relatively easy it is to implement those across all our application layers. We have discussed how to model our entities so collections are well managed. In summary, the parent is fully responsible for the creation and deletion of child instances. It is a good example of how our entities are moving away from just being simple CRUD data classes to more complex entities that implement business behavior.

We also discussed the NHibernate implementation and how easy it is at this point of the project creating new tests that automatically manage the new database schema, an aspect that proves to be invaluable. We also covered some MVVM techniques to leverage some common scenarios on the client side, like enable/disable action buttons using the predicates on the RelayCommand; once more, it was demonstrated how much value can be achieved by providing a rich model implementation to the XAML Views, reducing the amount of code-behind as a result of the XAML binding capabilities.

In the next chapter, we will discuss how easy it is to deploy our application to Microsoft Azure.

Appendix

Get the application running

For those that are new to the series or those who are not sure yet how to get the eDirectory application running, the following section describes the steps to quickly get the application running. eDirectory is an application that can be run in-memory or against a SQL Server database using an NHibernate repository implementation. Here, we discuss how to get the client running in a very easy manner: in-process in-memory mode.

In the first place, you need to verify that the client App.Config is set properly so SpringConfigFile is set to use the InMemoryConfiguration.xml file:

Ensure that the eDirectory.WPF application is set to be the start up one:

Change the configuration to the in-memory instance in Visual Studio:

Now the only thing you need is to start the application: F5 or CTRL+F5:

Couple WCF beauties

There are couple things done in this chapter on the WPF side that are worth a brief discussion. WCF by default terminates the client application when the first View that was created is closed. In this version of eDirectory, it is required to ask the user which View must be open. Once the user presses the OK button, the original screen must be closed; if nothing is done, the application terminates at that point. An easy way of stopping this behavior is to indicate to WPF that the application itself will look after its shutdown:

The Convert method is used to see if the radio-button must be set given an enumeration value; the method assumes that the radio-button is to be set if the parameter matches the passed value. ConvertBack returns null if the radio-button is not set; if it is set, it returns the enum value set in the XAML.

The XAML is as follows:

The converter is declared as a resource named enumConverter and then used in the radio-button declaration; an enum value is assigned to each; CurrentOption is a ViewTypeEnum property declared on the ViewModel that is correctly set without any other additional code. Nice!

AutoMapper

In this chapter, we decided to introduce AutoMapper. This is an object-to-object mapper, and it is ideal for use when dealing with domain entities and DTOs. You may want to have a look at the CodePlex project for further details.

It is quite easy to use AutoMapper. In the first place, we create the mappings, then we install them and then the mappings can be used. In the eDirectory.Domain project, a new class is added that declares the mappings:

Two mappings are defined, the mapping from Customer to CustomerDto is the interesting one. This one maps the DTO Addresses collection to a function that delegates into the other AutoMapper mapping to map the Addresses collection in the entity to a collection of AddressDto instances.

Then when the WCF service is started, the static Install method is invoked:

You can also leverage the Spring.Net capabilities to initialise the static method by just declaring the class in the configuration file; this is the approach used when we execute the application in in-memory mode; this is another nice example of the Spring.Net capabilities:

An example of how the eDirectory solution uses the AutoMapper mapping is found in the Customer service implementation:

Since CustomerDtos = IList CustomerDto and they both inherit DtoBase, when I return CustomerDtos, every entry in the list have a ResponseInstance with Busniess Exception and Warning, in addition to the one that belongs to the list. Is that what it supposed to be? Or do I use it wrong? Is it possible to have only one response instance for CustomerDtos?

We are not allowed to use NHibernate, so I'm wondering how difficult it is to implement an Entity Framework version of the sample. It should be simple in theory since you already have an in-memory version. But when I look at other Repository/Unit of Work samples using EF, nobody does transaction factory, context management and a few other things the way you did. It definitely looks more elegant. But I'm not sure if it's because some them are NHibernate specific. Or .NET crowd are not so advanced, or I haven't stumbled onto the right one.

Since CustomerDtos = IList CustomerDto and they both inherit DtoBase, when I return CustomerDtos, every entry in the list have a ResponseInstance with Busniess Exception and Warning, in addition to the one that belongs to the list. Is that what it supposed to be? Or do I use it wrong? Is it possible to have only one response instance for CustomerDtos?

I was trying to minimize the number of DTO implementations re-using the CustomerDto class. I should have been more careful as other people, like you, had similar questions. In sort, I should have a better model for my response objects and DTOs. In the case you mention; the only valid response when the list of customers is returned is the the one at the root, the individual customerDto instances will have "blank" responses.

If we were going to change the DTOs in the way you are suggesting (a better solution that my current approach), we would have something like the following for the Customer service interface:

So the CustomerDto class will not inherit from the DtoBase class anymore, instead the CustomerResponse inherits from DtoBase class and exposes a CustomerDto property working as a sort of wrapper. In order to accommodate this approach I will need to re-factor the DtoBase and ValidatorDtoBase classes ... inheritance is always a troublemaker

It is worth noting that the response Dto must implement the IDtoResponse interface but it does not really need to inherit from DtoBase.

tyzh wrote:

We are not allowed to use NHibernate, so I'm wondering how difficult it is to implement an Entity Framework version of the sample. It should be simple in theory since you already have an in-memory version.

I am going to be honest, my experience with EF is limited so I should not assume that the implementation is easy. It seems you have just set another challenge for the series, now I will have to implement an EF repository. Thanks

I would like to know what sort of argument is used to stop you from using NH instead of using EF. Again, I am not an expert in EF so I cannot compare them but I wonder how flexible EF is. I just checked some EF documentation in relation to your question and it concerns me when I see code like the following:

Could anyone explain how the TransctionScope relates to the DatabaseEntityModel instance? It seems to be just magic, it is not very explicit.

tyzh wrote:

But when I look at other Repository/Unit of Work samples using EF, nobody does transaction factory, context management and a few other things the way you did. It definitely looks more elegant. But I'm not sure if it's because some them are NHibernate specific. Or .NET crowd are not so advanced, or I haven't stumbled onto the right one.

One of the purposes for enabling the TransactionManager, the factory and the RepositoryLocator was to provide a layer of abstraction between the domain classes and the persistence back-end. So the same model should be applicable to an EF implementation. I just looked briefly to some EF documentation and I can see that in order to achieve the functionality that NH exposes on the Session class, you may need to leverage the use of the ObjectContext, TransactionScope (maybe this one is not required) and possibly EntityConnection. I worked out that assumption from the following links:

Thanks for the update. Minimizing number of classes are also important to me. Our team came from stored procedure to web page background, I often have to justify why my code is longer than theirs

Now that I think it again, even without the extra coding, there are still good use cases. For example, I have a message list dto, which is not a list of messages. So in that case, maybe the MessageListViewDto do not need to inherit DtoBase, just the MessageListViewDtoS does.

We are not allowed to use anything that does not come from the mother ship, case closed But at least I have waited long enough now that EF Code First CTP5 is out, which is pretty close to NHibernate ... on the surface.

I have been playing with this framework Huyrua created and trying to integrate some of your stuff. Right now, I'm trying to figure out how to stuff global context and business notifier in there

He seems to take a more simplified and practical approach, so there are some hard dependencies on EF and WCF (Or maybe I couldn't understand his framework and use it at face value, or wrong altogether )

Again, thanks for the great work. It's a nice feeling to learn new things, even though it's quite overwhelming from time to time.

Not sure if I should ask here or at the relevant chapters. They are probably too basic anywhere, hope you don't mind

In Domain.CustomerService, why only Delete and FindAll Command have the relevant BusinessWarning logic, but Update and GetById don't? Are they hidden somewhere else? Also seems the BusinessWarnings are used as regular acknowledgment rather something to warn, is that what it intended?

I never used NHibernate. In .NET, there's usually try catch everywhere, are they handled differently here? Say if the database is down, how is it handled? Are the message get into Business Exception? And where does this happen? I saw some in the transaction manager, but what about a simple retrieval that end up with a database error?

On an unrelated topic, I saw some repository implementation where all CRUD operation are in the repository. So you have CustomerRepository.Create vs Customer.Create. Are there any real difference here?

In Domain.CustomerService, why only Delete and FindAll Command have the relevant BusinessWarning logic, but Update and GetById don't? Are they hidden somewhere else?

To be honest, I was to lazy to implement comprehensive business logic for all the possible scenarios. I was just waiting for someone to notice, thanks

tyzh wrote:

Also seems the BusinessWarnings are used as regular acknowledgment rather something to warn, is that what it intended?

If you get the latest code at CodePlex the business warnings are implemented on the client side, but in a nutshell, warnings provide information to the user but they do not stop business processing.

tyzh wrote:

I never used NHibernate. In .NET, there's usually try catch everywhere, are they handled differently here? Say if the database is down, how is it handled? Are the message get into Business Exception? And where does this happen? I saw some in the transaction manager, but what about a simple retrieval that end up with a database error?

This is an excellent question, in the case you indicate, the TransactionManager currently re-throws the exception back to the client after rolling back the transaction if possible. In the client side we have two possible outcomes. If the WCF includeExceptionDetailInFaults setting is enabled, then the client will display the exception in the client, if this is not the case, WCF hides the exception with a general description.

What we normally do in these cases is to "enhance" the transaction manager so BusinessExceptions are used for well-known scenarios or even for any managed exceptions in the server side.

tyzh wrote:

On an unrelated topic, I saw some repository implementation where all CRUD operation are in the repository. So you have CustomerRepository.Create vs Customer.Create. Are there any real difference here?

As indicated before in the series, the business entities hide their constructors so an static Create method is required. The main two reasons for having this one declared within the entity are that you may require some pre/post validation that should be placed on the entity itself (it is not the responsibility of the repository to validate); the second reason is to minimise the number of the repository implementations declared within the solution instead of using generic repositories.