C#.NET: does TransactionScope object synchronizes the access to code among multiple threads of users ?

458 views Asked by At

Does the TransactionScope object also synchronizes the access to code among Multiple threads of Users ? OR, it only declares the code (Business Operations) as atomic (single Transaction)?

Details: 1. I am implementing UnitOfWork class for Repositories in Infrastructure Layer which itself is defined as class library project (dll).

  1. Repository contains reference to object of UnitOfWork to call its methods which maintain diciontary/collection of Entities that has been added, changed Or updated.

  2. Unit of Work class has a member function Commits() which has the code wrapped inside TransactionScope object.

Consider that Multiple users access the Domain/Business objects then i presume that each user will have its own set of business objects running in its thread.

I am not sure what TransactionScope object will do in this case ? Is it just decalring the multiple operations inside a user thread as single business transaction ? OR it is synchronizing the acess to code also among different threads of user/s? The code of UnitOfWork class is as below:

public class UnitOfWork
{
    private Dictionary<EntityBase, IUnitOfWorkRepository> addedEntities;
    private Dictionary<EntityBase, IUnitOfWorkRepository> changedEntities;
    private Dictionary<EntityBase, IUnitOfWorkRepository> deletedEntities;

    public UnitOfWork()
    {
        this.addedEntities = new Dictionary<EntityBase, IUnitOfWorkRepository>();
        this.changedEntities = new Dictionary<EntityBase, IUnitOfWorkRepository>();
        this.deletedEntities = new Dictionary<EntityBase, IUnitOfWorkRepository>();
    }

    #region IUnitOfWork Members

    public void RegisterAdded(EntityBase entity, IUnitOfWorkRepository repository)
    {
        this.addedEntities.Add(entity, repository);
    }

    public void RegisterChanged(EntityBase entity, IUnitOfWorkRepository repository)
    {
        this.changedEntities.Add(entity, repository);
    }

    public void RegisterRemoved(EntityBase entity, IUnitOfWorkRepository repository)
    {
        this.deletedEntities.Add(entity, repository);
    }

    public void Commit()
    {
        using (TransactionScope scope = new TransactionScope())
        {
            foreach (EntityBase entity in this.deletedEntities.Keys)
            {
                this.deletedEntities[entity].PersistDeletedItem(entity);
            }

            foreach (EntityBase entity in this.addedEntities.Keys)
            {
                this.addedEntities[entity].PersistDeletedItem(entity);
            }

            foreach (EntityBase entity in this.changedEntities.Keys)
            {
                this.changedEntities[entity].PersistDeletedItem(entity);
            }

            scope.Complete();
        }

        this.deletedEntities.Clear();

        this.addedEntities.Clear();

        this.changedEntities.Clear();
    }
    #endregion
}
2

There are 2 answers

0
Fakhar Anwar On
  1. My question is alse answered in this link under example heading P11: http://www.codeproject.com/Articles/18743/Interfaces-in-C-For-Beginners

  2. The reason for asking this question was just to confirm the Object Oriented Rule on interface that was stated during discussion on Domain Driven Design book in whihc Repositoary Factory class returns a generic type of IRepository which also means that the RepositoryFactory will be able to return IRepository OR any interface OR Class extending IRepository in addition to implementing it (That is how i think .NET generics are interpreted ( full code and discussion is below).

---Discussion STARTS here---

--Code

using System;
using System.Collections.Generic;
using SmartCA.Infrastructure;
using SmartCA.Infrastructure.DomainBase;
using SmartCA.Infrastructure.RepositoryFramework.Configuration;
using System.Configuration;
namespace SmartCA.Infrastructure.RepositoryFramework
{
public static class RepositoryFactory
{
// Dictionary to enforce the singleton pattern
private static Dictionary < string, object > repositories = new
Dictionary < string, object > ();
/// < summary >
/// Gets or creates an instance of the requested interface. Once a
/// repository is created and initialized, it is cached, and all
/// future requests for the repository will come from the cache.
/// < /summary >
/// < typeparam name=”TRepository” > The interface of the repository
/// to create. < /typeparam >
/// < typeparam name=”TEntity” > The type of the EntityBase that the
/// repository is for. < /typeparam >
/// < returns > An instance of the interface requested. < /returns >
public static TRepository GetRepository < TRepository, TEntity > ()
where TRepository : class, IRepository < TEntity >
where TEntity : EntityBase
{
// Initialize the provider’s default value
TRepository repository = default(TRepository);
string interfaceShortName = typeof(TRepository).Name;
// See if the provider was already created and is in the cache
if (!RepositoryFactory.repositories.ContainsKey(interfaceShortName))
{
// Not there, so create it
// Get the repositoryMappingsConfiguration config section
RepositorySettings settings =
(RepositorySettings)ConfigurationManager.GetSection(RepositoryMappingConstants
.RepositoryMappingsConfigurationSectionName);
// Create the repository, and cast it to the interface specified
repository =
Activator.CreateInstance(Type.GetType(settings.RepositoryMappings[interfaceShortName]
.RepositoryFullTypeName)) as TRepository;
// Add the new provider instance to the cache
RepositoryFactory.repositories.Add(interfaceShortName, repository);
}
else
{
// The provider was in the cache, so retrieve it
repository =
(TRepository)RepositoryFactory.repositories[interfaceShortName];
}
return repository;
}
}
}

--Code

The signature of this method is interesting because it uses two Generic type parameters, TRepository and TEntity , with the restrictions that TRepository is a class and implements the IRepository < TEntity > interface, and that TEntity derives from the EntityBase class. Because the Repository Framework is supporting interfaces other than just IRepository < T > , the method cannot just return a type of IRepository < T > for the Repository instance. It must also support returning any interface that implements IRepository < T > , since the repository interface being used can also have additional methods defined in it; that is why TRepository has been declared as a Generic type, so that the factory can support the Repository Framework requirements of being able to pass in a valid Repository interface type and get an instance of the interface (as long as it has been properly defined in the application ’ s configuration file).

---Discussion ENDS here---

0
Fakhar Anwar On

@ Adil Mughal: Great thanks, your prompt answer really helps. For futher details on what is term "thread-safe" in context of C#.NET, i also got some useful links and would like to share below: (From this what i get is that TransactionScope object is "thread-safe" which means anycode in TransactionScope object block is well-synchronised by .NET and multiple threads accessing the block of code cannot create concurrency problems, like it puts lock on theblock of code)

What "thread safe" really means...In Practical terms

What Makes a Method Thread-safe? What are the rules?

Thread safe collections in .NET

http://www.codeproject.com/Articles/37976/Writing-Thread-Safe-Code-in-C

http://www.albahari.com/threading/part2.aspx

Regards, Fakhar Anwar