3. Database Transactions

In this tutorial, you will create an update service and learn about how Gazel manages database transactions.

To complete this tutorial download previous solution from here or jump to previous tutorial.

Business Service on Persistent Objects

Now that you've created tasks, it's time to complete them. To do this add following method to your Task class.

public class Task { ... public virtual void Complete() { Completed = true; } ... } ...

And that's it. You've created a Complete service.

There is no need to create a database transaction, before every service call Gazel automatically opens a database connection and begins a transaction.

Notice that you don't have to call an update method in repository. Gazel configures NHibernate to make a dirty check upon commit and update rows when there is a change.

Build and run AppHost.Service again. Now you will see a Task service package and under this package there is Complete service. Since this service requires a row in database, Id parameter is added automatically.

Go and create a task using Task Manager/Create Task and use that object's Id in Target/Id field of Complete service.

When you press call button you will see following screen;

Important note on protected setters

You may remember that we used protected access modifier on property setters as shown below;

public class Task { ... public virtual int Id { get; protected set; } public virtual string Name { get; protected set; } public virtual bool Completed { get; protected set; } ... } ...

If you don't do this, technically nothing changes. There is nothing in Gazel that will prevent you from doing this. However, the main idea behind writing business services on persistent classes is to enable developers to collect all services for an entity into one source code file. This may sound weird, but consider this;

If you have all of your properties to have public setters, this would make it possible for any class from any module to update a property value. Let's use Task class's Completed property for an instance. When the setter is public, it is most likely for you to have several services that set Completed to true.

This is not a problem unless you decide to create a business logic on completion of a task. Let's say the user story is "I want to notify watchers of the task when it is completed". In this case, you will either trace all your code and refactor all Completed updates into one place, or you can create an interceptor-like logic to achieve that. Former is a waste, latter is unnecessarily complex.

To avoid this, we prefer to have those kind of updates within the owner class of a property, in this case Task class, so that we can write business logic like the following;

public class Task { ... public virtual void Complete() { Completed = true; notifier.SendMail( GetWatchers(), string.Format("{0} task is completed", Name) ); } ... } ...

Above source code will not compile if you include it in your solution. This code is just an example for this section.

Testing an Update Service

Let's move on to unit testing. Now add following test to your TaskTest test class;

[TestFixture] public class TaskTest : TestBase { ... [Test] public void CompleteTask__marks_task_as_completed() { var taskManager = Context.Get<TaskManager>(); var task = taskManager.CreateTask("Write Tests"); BeginTest(); task.Complete(); Assert.IsTrue(task.Completed); } }

Here's what you've done;

  • Get TaskManager object and create a task named "Write Tests": arrange
  • Complete the new Task object: act
  • Assert that task is completed: assert

Note that this time CreateTask is moved before BeginTest(). This is because for this test case creating a task is a part of arrange step.

Summary

When you add business services to persistent classes, you'll see that almost all of your business logic goes into persistent classes.

Now try to add new properties and methods to your persistent classes, re-run and see the results.

Once you are ready, you can proceed to next page to learn how to write query services.


You can download complete source code for this tutorial here