/// <summary>
        /// Updates an existing binary property value in the database and the blob storage.
        /// </summary>
        /// <param name="blobProvider">Blob storage provider.</param>
        /// <param name="value">Binary data to update.</param>
        public void UpdateBinaryProperty(IBlobProvider blobProvider, BinaryDataValue value)
        {
            var streamLength = value.Stream?.Length ?? 0;

            if (blobProvider != BlobStorageBase.BuiltInProvider && streamLength > 0)
            {
                var ctx = new BlobStorageContext(blobProvider, value.BlobProviderData)
                {
                    VersionId      = 0,
                    PropertyTypeId = 0,
                    FileId         = value.FileId,
                    Length         = streamLength,
                };

                blobProvider.Allocate(ctx);
                using (var stream = blobProvider.GetStreamForWrite(ctx))
                    value.Stream?.CopyTo(stream);

                value.BlobProviderName = ctx.Provider.GetType().FullName;
                value.BlobProviderData = BlobStorageContext.SerializeBlobProviderData(ctx.BlobProviderData);
            }
            else
            {
                value.BlobProviderName = null;
                value.BlobProviderData = null;
            }

            if (blobProvider == BlobStorageBase.BuiltInProvider)
            {
                // MS-SQL does not support stream size over [Int32.MaxValue].
                if (streamLength > int.MaxValue)
                {
                    throw new NotSupportedException();
                }
            }

            var isRepositoryStream = value.Stream is RepositoryStream;
            var hasStream          = isRepositoryStream || value.Stream is MemoryStream;

            if (!hasStream)
            {
                // do not do any database operation if the stream is not modified
                return;
            }

            SqlProcedure cmd = null;

            try
            {
                string      sql;
                CommandType commandType;
                if (blobProvider == BlobStorageBase.BuiltInProvider)
                {
                    commandType = CommandType.StoredProcedure;
                    sql         = "proc_BinaryProperty_Update";
                }
                else
                {
                    commandType = CommandType.Text;
                    sql         = UpdateBinaryPropertyNewFilerowScript;
                }

                cmd = new SqlProcedure {
                    CommandText = sql, CommandType = commandType
                };
                cmd.Parameters.Add("@BinaryPropertyId", SqlDbType.Int).Value      = value.Id;
                cmd.Parameters.Add("@ContentType", SqlDbType.NVarChar, 450).Value = value.ContentType;
                cmd.Parameters.Add("@FileNameWithoutExtension", SqlDbType.NVarChar, 450).Value = value.FileName.FileNameWithoutExtension == null ? DBNull.Value : (object)value.FileName.FileNameWithoutExtension;
                cmd.Parameters.Add("@Extension", SqlDbType.NVarChar, 50).Value     = ValidateExtension(value.FileName.Extension);
                cmd.Parameters.Add("@Size", SqlDbType.BigInt).Value                = value.Size;
                cmd.Parameters.Add("@Checksum", SqlDbType.VarChar, 200).Value      = value.Checksum != null ? (object)value.Checksum : DBNull.Value;
                cmd.Parameters.Add("@BlobProvider", SqlDbType.NVarChar, 450).Value = value.BlobProviderName != null ? (object)value.BlobProviderName : DBNull.Value;
                cmd.Parameters.Add("@BlobProviderData", SqlDbType.NVarChar, int.MaxValue).Value = value.BlobProviderData != null ? (object)value.BlobProviderData : DBNull.Value;

                var fileId = (int)cmd.ExecuteScalar();
                if (fileId > 0 && fileId != value.FileId)
                {
                    value.FileId = fileId;
                }
            }
            finally
            {
                cmd.Dispose();
            }

            // ReSharper disable once InvertIf
            if (blobProvider == BlobStorageBase.BuiltInProvider && !isRepositoryStream && streamLength > 0)
            {
                // Stream exists and is loaded -> write it
                var ctx = new BlobStorageContext(blobProvider, value.BlobProviderData)
                {
                    VersionId        = 0,
                    PropertyTypeId   = 0,
                    FileId           = value.FileId,
                    Length           = streamLength,
                    BlobProviderData = new BuiltinBlobProviderData()
                };

                BuiltInBlobProvider.UpdateStream(ctx, value.Stream);
            }
        }
        /// <summary>
        /// Updates an existing binary property value in the database and the blob storage.
        /// </summary>
        /// <param name="blobProvider">Blob storage provider.</param>
        /// <param name="value">Binary data to update.</param>
        public void UpdateBinaryProperty(IBlobProvider blobProvider, BinaryDataValue value)
        {
            var streamLength = value.Stream?.Length ?? 0;

            if (blobProvider != BlobStorageBase.BuiltInProvider && streamLength > 0)
            {
                var ctx = new BlobStorageContext(blobProvider, value.BlobProviderData)
                {
                    VersionId      = 0,
                    PropertyTypeId = 0,
                    FileId         = value.FileId,
                    Length         = streamLength,
                    UseFileStream  = false
                };

                blobProvider.Allocate(ctx);
                using (var stream = blobProvider.GetStreamForWrite(ctx))
                    value.Stream?.CopyTo(stream);

                value.BlobProviderName = ctx.Provider.GetType().FullName;
                value.BlobProviderData = BlobStorageContext.SerializeBlobProviderData(ctx.BlobProviderData);
            }
            else
            {
                value.BlobProviderName = null;
                value.BlobProviderData = null;
            }

            if (blobProvider == BlobStorageBase.BuiltInProvider && !BlobStorage.FileStreamEnabled)
            {
                // MS-SQL does not support stream size over [Int32.MaxValue],
                // but check only if Filestream is not enabled
                if (streamLength > int.MaxValue)
                {
                    throw new NotSupportedException();
                }
            }

            var isRepositoryStream = value.Stream is RepositoryStream || value.Stream is SenseNetSqlFileStream;
            var hasStream          = isRepositoryStream || value.Stream is MemoryStream;

            if (!hasStream)
            {
                // do not do any database operation if the stream is not modified
                return;
            }

            FileStreamData fileStreamData = null;
            SqlProcedure   cmd            = null;

            try
            {
                string      sql;
                CommandType commandType;
                if (blobProvider == BlobStorageBase.BuiltInProvider)
                {
                    commandType = CommandType.StoredProcedure;
                    sql         = "proc_BinaryProperty_Update";
                }
                else
                {
                    commandType = CommandType.Text;
                    sql         = BlobStorage.FileStreamEnabled
                        ? UpdateBinarypropertyNewFilerowFilestreamScript
                        : UpdateBinarypropertyNewFilerowScript;
                }

                cmd = new SqlProcedure {
                    CommandText = sql, CommandType = commandType
                };
                cmd.Parameters.Add("@BinaryPropertyId", SqlDbType.Int).Value      = value.Id;
                cmd.Parameters.Add("@ContentType", SqlDbType.NVarChar, 450).Value = value.ContentType;
                cmd.Parameters.Add("@FileNameWithoutExtension", SqlDbType.NVarChar, 450).Value = value.FileName.FileNameWithoutExtension == null ? DBNull.Value : (object)value.FileName.FileNameWithoutExtension;
                cmd.Parameters.Add("@Extension", SqlDbType.NVarChar, 50).Value     = ValidateExtension(value.FileName.Extension);
                cmd.Parameters.Add("@Size", SqlDbType.BigInt).Value                = value.Size;
                cmd.Parameters.Add("@Checksum", SqlDbType.VarChar, 200).Value      = value.Checksum != null ? (object)value.Checksum : DBNull.Value;
                cmd.Parameters.Add("@BlobProvider", SqlDbType.NVarChar, 450).Value = value.BlobProviderName != null ? (object)value.BlobProviderName : DBNull.Value;
                cmd.Parameters.Add("@BlobProviderData", SqlDbType.NVarChar, int.MaxValue).Value = value.BlobProviderData != null ? (object)value.BlobProviderData : DBNull.Value;

                int fileId;
                if (BlobStorage.FileStreamEnabled)
                {
                    string path;
                    byte[] transactionContext;

                    // Update row and retrieve file path and
                    // transaction context for the Filestream column
                    using (var reader = cmd.ExecuteReader())
                    {
                        reader.Read();

                        fileId             = reader.GetInt32(0);
                        path               = reader.GetSafeString(1);
                        transactionContext = reader.IsDBNull(2) ? null : reader.GetSqlBytes(2).Buffer;
                    }

                    if (!string.IsNullOrEmpty(path))
                    {
                        fileStreamData = new FileStreamData {
                            Path = path, TransactionContext = transactionContext
                        }
                    }
                    ;
                }
                else
                {
                    fileId = (int)cmd.ExecuteScalar();
                }
                if (fileId > 0 && fileId != value.FileId)
                {
                    value.FileId = fileId;
                }
            }
            finally
            {
                cmd?.Dispose();
            }

            // ReSharper disable once InvertIf
            if (blobProvider == BlobStorageBase.BuiltInProvider && !isRepositoryStream && streamLength > 0)
            {
                // Stream exists and is loaded -> write it
                var ctx = new BlobStorageContext(blobProvider, value.BlobProviderData)
                {
                    VersionId        = 0,
                    PropertyTypeId   = 0,
                    FileId           = value.FileId,
                    Length           = streamLength,
                    UseFileStream    = fileStreamData != null,
                    BlobProviderData = new BuiltinBlobProviderData {
                        FileStreamData = fileStreamData
                    }
                };

                BuiltInBlobProvider.UpdateStream(ctx, value.Stream);
            }
        }