/// <summary>
        /// Find existing instance of ProcessManager
        /// FindData() and UpdateData() are part of the same transaction.
        /// FindData() opens new connection and transaction.
        /// UPDLOCK is placed onf the relevant row to prevent reads until the transaction is commited in UpdateData
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IPersistanceData <T> FindData <T>(IProcessManagerPropertyMapper mapper, Message message) where T : class, IProcessManagerData
        {
            var mapping = mapper.Mappings.FirstOrDefault(m => m.MessageType == message.GetType()) ??
                          mapper.Mappings.First(m => m.MessageType == typeof(Message));

            string tableName = typeof(T).Name;

            var sbXPath = new StringBuilder();

            sbXPath.Append("(/" + tableName);
            foreach (var prop in mapping.PropertiesHierarchy.Reverse())
            {
                sbXPath.Append("/" + prop.Key);
            }
            sbXPath.Append(")[1]");

            XPathExpression xPathExpression;

            try
            {
                xPathExpression = XPathExpression.Compile(sbXPath.ToString());
            }
            catch (XPathException ex)
            {
                Logger.ErrorFormat("Error compiling xpath expression. {0}", ex.Message);
                throw;
            }

            // Message Propery Value
            object msgPropValue = mapping.MessageProp.Invoke(message);

            SqlServerData <T> result = null;

            if (!GetTableNameExists(tableName))
            {
                return(null);
            }

            using (var sqlConnection = new SqlConnection(_connectionString))
            {
                sqlConnection.Open();

                using (var command = new SqlCommand())
                {
                    command.Connection     = sqlConnection;
                    command.CommandTimeout = _commandTimeout;
                    command.CommandText    = string.Format(@"SELECT * FROM {0} WHERE DataXml.value('{1}', 'nvarchar(max)') = @val", tableName, xPathExpression.Expression);
                    command.Parameters.Add(new SqlParameter {
                        ParameterName = "@val", Value = msgPropValue
                    });

                    try
                    {
                        var reader = command.ExecuteReader(CommandBehavior.SingleResult);

                        if (reader.HasRows)
                        {
                            reader.Read();

                            var    serializer = new XmlSerializer(typeof(T));
                            object res;
                            using (TextReader r = new StringReader(reader["DataXml"].ToString()))
                            {
                                res = serializer.Deserialize(r);
                            }

                            result = new SqlServerData <T>
                            {
                                Id      = (Guid)reader["Id"],
                                Data    = (T)res,
                                Version = (int)reader["Version"]
                            };
                        }

                        reader.Dispose();
                    }
                    finally
                    {
                        sqlConnection.Close();
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// Create new instance of ProcessManager
        /// When multiple threads try to create new ProcessManager instance, only the first one is allowed.
        /// All subsequent threads will update data instead.
        /// </summary>
        /// <param name="data"></param>
        public void InsertData(IProcessManagerData data)
        {
            string tableName = GetTableName(data);

            var sqlServerData = new SqlServerData <IProcessManagerData>
            {
                Data    = data,
                Version = 1,
                Id      = data.CorrelationId
            };

            var       xmlSerializer = new XmlSerializer(data.GetType());
            var       sww           = new StringWriter();
            XmlWriter writer        = XmlWriter.Create(sww);

            xmlSerializer.Serialize(writer, data);
            var dataXml = sww.ToString();

            using (var sqlConnection = new SqlConnection(_connectionString))
            {
                sqlConnection.Open();

                using (var dbTransaction = sqlConnection.BeginTransaction(IsolationLevel.ReadCommitted))
                {
                    // Insert if doesn't exist, else update (only the first one is allowed)
                    string upsertSql = string.Format(@"if exists (select * from {0} with (updlock,serializable) WHERE Id = @Id)
                                                    begin
                                                        UPDATE {0}
		                                                SET DataXml = @DataXml, Version = @Version 
		                                                WHERE Id = @Id
                                                    end
                                                else
                                                    begin
                                                        INSERT {0} (Id, Version, DataXml)
                                                        VALUES (@Id,@Version,@DataXml)
                                                    end", tableName);


                    using (var command = new SqlCommand(upsertSql))
                    {
                        command.Connection  = sqlConnection;
                        command.Transaction = dbTransaction;
                        command.Parameters.Add("@Id", SqlDbType.UniqueIdentifier).Value = data.CorrelationId;
                        command.Parameters.Add("@Version", SqlDbType.Int).Value         = sqlServerData.Version;
                        command.Parameters.Add("@DataXml", SqlDbType.Xml).Value         = dataXml;

                        try
                        {
                            command.ExecuteNonQuery();
                            dbTransaction.Commit();
                        }
                        catch
                        {
                            dbTransaction.Rollback();
                            throw;
                        }
                        finally
                        {
                            sqlConnection.Close();
                        }
                    }
                }
            }
        }